﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

// Процедура-обработчик события "ПередЗаписью" документов для механизма регистрации объектов на узлах.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого выполняется механизм регистрации.
//  Источник       - ДокументОбъект - источник события.
//  Отказ          - Булево - флаг отказа от выполнения обработчика.
//  РежимЗаписи - РежимЗаписиДокумента - см. в синтакс-помощнике РежимЗаписиДокумента.
//  РежимПроведения - РежимПроведенияДокумента - см. в синтакс-помощнике РежимПроведенияДокумента.
// 
Процедура МеханизмРегистрацииОбъектовПередЗаписьюДокумента(ИмяПланаОбмена, Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
	
	Если Источник.ДополнительныеСвойства.Свойство("ОтключитьМеханизмРегистрацииОбъектов")
	   И Не Источник.ДополнительныеСвойства.Свойство("РегистрироватьНаУзлахПлановОбменаПриОбновленииИБ") Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЗащитаПерсональныхДанных") Тогда
		
		Модуль = ОбщегоНазначения.ОбщийМодуль("ЗащитаПерсональныхДанных");
		Если Модуль.ПропуститьРегистрациюОбъекта(ИмяПланаОбмена, Источник) Тогда
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
	
	ДополнительныеПараметры = Новый Структура("РежимЗаписи", РежимЗаписи);
	ЗарегистрироватьИзменениеОбъекта(ИмяПланаОбмена, Источник, Отказ, ДополнительныеПараметры);
	
КонецПроцедуры

// Процедура-обработчик события "ПередЗаписью" ссылочных типов данных (кроме документов) для механизма регистрации
// объектов на узлах.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого выполняется механизм регистрации.
//  Источник       - СправочникОбъект
//                 - ПланВидовХарактеристикОбъект - источник события, кроме типа ДокументОбъект.
//  Отказ          - Булево - флаг отказа от выполнения обработчика.
// 
Процедура МеханизмРегистрацииОбъектовПередЗаписью(ИмяПланаОбмена, Источник, Отказ) Экспорт
	
	Если Источник.ДополнительныеСвойства.Свойство("ОтключитьМеханизмРегистрацииОбъектов")
	   И Не Источник.ДополнительныеСвойства.Свойство("РегистрироватьНаУзлахПлановОбменаПриОбновленииИБ") Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЗащитаПерсональныхДанных") Тогда
		
		Модуль = ОбщегоНазначения.ОбщийМодуль("ЗащитаПерсональныхДанных");
		Если Модуль.ПропуститьРегистрациюОбъекта(ИмяПланаОбмена, Источник) Тогда
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
	
	ЗарегистрироватьИзменениеОбъекта(ИмяПланаОбмена, Источник, Отказ);
	
КонецПроцедуры

// Процедура-обработчик события "ПередЗаписью" регистров для механизма регистрации объектов на узлах.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого выполняется механизм регистрации.
//  Источник       - НаборЗаписейРегистра - источник события.
//  Отказ          - Булево - флаг отказа от выполнения обработчика.
//  Замещение      - Булево - признак замещения существующего набора записей.
// 
Процедура МеханизмРегистрацииОбъектовПередЗаписьюРегистра(ИмяПланаОбмена, Источник, Отказ, Замещение) Экспорт
	
	Если Источник.ДополнительныеСвойства.Свойство("ОтключитьМеханизмРегистрацииОбъектов")
	   И Не Источник.ДополнительныеСвойства.Свойство("РегистрироватьНаУзлахПлановОбменаПриОбновленииИБ") Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЗащитаПерсональныхДанных") Тогда
		
		Модуль = ОбщегоНазначения.ОбщийМодуль("ЗащитаПерсональныхДанных");
		Если Модуль.ПропуститьРегистрациюОбъекта(ИмяПланаОбмена, Источник) Тогда
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
	
	ДополнительныеПараметры = Новый Структура("ЭтоРегистр,Замещение", Истина, Замещение);
	ЗарегистрироватьИзменениеОбъекта(ИмяПланаОбмена, Источник, Отказ, ДополнительныеПараметры);
	
КонецПроцедуры

// Процедура-обработчик события "ПередЗаписью" константы для механизма регистрации объектов на узлах.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого выполняется механизм регистрации.
//  Источник       - КонстантаМенеджерЗначения - источник события.
//  Отказ          - Булево - флаг отказа от выполнения обработчика.
// 
Процедура МеханизмРегистрацииОбъектовПередЗаписьюКонстанты(ИмяПланаОбмена, Источник, Отказ) Экспорт
	
	Если Источник.ДополнительныеСвойства.Свойство("ОтключитьМеханизмРегистрацииОбъектов")
	   И Не Источник.ДополнительныеСвойства.Свойство("РегистрироватьНаУзлахПлановОбменаПриОбновленииИБ") Тогда
		Возврат;
	КонецЕсли;
	
	ДополнительныеПараметры = Новый Структура("ЭтоКонстанта", Истина);
	ЗарегистрироватьИзменениеОбъекта(ИмяПланаОбмена, Источник, Отказ, ДополнительныеПараметры);
	
КонецПроцедуры

// Процедура-обработчик события "ПередУдалением" ссылочных типов данных для механизма регистрации объектов на узлах.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого выполняется механизм регистрации.
//  Источник       - СправочникОбъект
//                 - ДокументОбъект
//                 - ПланВидовХарактеристикОбъект - источник события.
//  Отказ          - Булево - флаг отказа от выполнения обработчика.
// 
Процедура МеханизмРегистрацииОбъектовПередУдалением(ИмяПланаОбмена, Источник, Отказ) Экспорт
	
	Если Источник.ДополнительныеСвойства.Свойство("ОтключитьМеханизмРегистрацииОбъектов")
	   И Не Источник.ДополнительныеСвойства.Свойство("РегистрироватьНаУзлахПлановОбменаПриОбновленииИБ") Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЗащитаПерсональныхДанных") Тогда
		
		Модуль = ОбщегоНазначения.ОбщийМодуль("ЗащитаПерсональныхДанных");
		Если Модуль.ПропуститьРегистрациюОбъекта(ИмяПланаОбмена, Источник) Тогда
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
	
	ДополнительныеПараметры = Новый Структура("ЭтоУдалениеОбъекта", Истина);
	ЗарегистрироватьИзменениеОбъекта(ИмяПланаОбмена, Источник, Отказ, ДополнительныеПараметры);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции для использования в обработчиках событий правил регистрации.

// Процедура дополняет список узлов-получателей объекта переданными значениями.
//
// Параметры:
//   Объект - СправочникОбъект
//          - ДокументОбъект - объект, для которого выполняется правило регистрации.
//   Узлы   - Массив из ПланОбменаСсылка - узлы плана обмена, которые необходимо добавить в список узлов-получателей объекта.
//
Процедура ДополнитьПолучателей(Объект, Узлы) Экспорт
	
	Для Каждого Элемент Из Узлы Цикл
		
		Попытка
			Объект.ОбменДанными.Получатели.Добавить(Элемент);
		Исключение
			ИмяПланаОбмена   = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(Элемент);
			ОбъектМетаданных = Объект.Метаданные();
			СтрокаСообщения  = НСтр("ru = 'Для состава плана обмена [ИмяПланаОбмена] не указана регистрация объекта [ПолноеИмя]'");
			СтрокаСообщения  = СтрЗаменить(СтрокаСообщения, "[ИмяПланаОбмена]", ИмяПланаОбмена);
			СтрокаСообщения  = СтрЗаменить(СтрокаСообщения, "[ПолноеИмя]",      ОбъектМетаданных.ПолноеИмя());
			ВызватьИсключение СтрокаСообщения;
		КонецПопытки;
		
	КонецЦикла;
	
КонецПроцедуры

// Процедура вычитает из списка узлов-получателей объекта переданные значения.
//
// Параметры:
//   Объект - СправочникОбъект
//          - ДокументОбъект - объект, для которого выполняется правило регистрации.
//   Узлы - Массив из ПланОбменаСсылка - узлы плана обмена, которые необходимо вычесть из списка узлов-получателей объекта.
// 
Процедура СократитьПолучателей(Объект, Узлы) Экспорт
	
	Получатели = СократитьМассив(Объект.ОбменДанными.Получатели, Узлы);
	
	// Очищаем список получателей и заполняем его заново.
	Объект.ОбменДанными.Получатели.Очистить();
	
	// Добавляем узлы для регистрации объекта.
	ДополнитьПолучателей(Объект, Получатели);
	
КонецПроцедуры

// Определяет массив узлов-получателей для объекта при заданном плане обмена и выполняет регистрацию объекта на
// полученных узлах.
//
// Параметры:
//  Объект         - Произвольный - СправочникОбъект, ДокументОбъект и т.п. объект, для которого необходимо выполнить
//                   правила регистрации, и выполнить регистрацию на узлах.
//  ИмяПланаОбмена - Строка - имя плана обмена как оно задано в конфигураторе.
//  Отправитель    - ПланОбменаСсылка - узел плана обмена от которого принимается сообщение обмена.
//                    Если задан, то регистрация объекта не этом узле выполнятся не будет.
// 
Процедура ВыполнитьПравилаРегистрацииДляОбъекта(Объект, ИмяПланаОбмена, Отправитель = Неопределено) Экспорт
	
	Получатели = ОпределитьПолучателей(Объект, ИмяПланаОбмена);
	
	ОбщегоНазначенияКлиентСервер.УдалитьЗначениеИзМассива(Получатели, Отправитель);
	
	Если Получатели.Количество() > 0 Тогда
		
		ПланыОбмена.ЗарегистрироватьИзменения(Получатели, Объект);
		
	КонецЕсли;
	
КонецПроцедуры

// Вычитает один массив элементов из другого массива. Возвращает результат вычитания.
//
// Параметры:
//  Массив - Массив из Произвольный - исходный массив.
//  МассивВычитания - Массив из Произвольный - массив, вычитаемый из исходного массива.
//
// Возвращаемое значение:
//   Массив из Произвольный - результат  вычитания.
//
Функция СократитьМассив(Массив, МассивВычитания) Экспорт
	
	Возврат ОбщегоНазначенияКлиентСервер.РазностьМассивов(Массив, МассивВычитания);
	
КонецФункции

// Функция возвращает список всех узлов заданного плана обмена кроме предопределенного узла.
//
// Параметры:
//   ИмяПланаОбмена - Строка - имя плана обмена, как оно задано в конфигураторе,
//                    список узлов для которого необходимо получить.
//
// Возвращаемое значение:
//   Массив из ПланОбменаСсылка - список всех узлов заданного плана обмена.
//
Функция ВсеУзлыПланаОбмена(ИмяПланаОбмена) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Возврат ОбменДаннымиСервер.УзлыПланаОбмена(ИмяПланаОбмена);
	
КонецФункции

// Функция определяет массив узлов-получателей для объекта при заданном плане обмена.
//
// Параметры:
//   Объект         - Произвольный - СправочникОбъект, ДокументОбъект и т.п. объект, для которого необходимо выполнить
//                    правила регистрации, и определить список узлов-получателей.
//   ИмяПланаОбмена - Строка - имя плана обмена как оно задано в конфигураторе.
// 
// Возвращаемое значение:
//   Массив из ПланОбменаСсылка - массив узлов-получателей для объекта.
//
Функция ОпределитьПолучателей(Объект, ИмяПланаОбмена) Экспорт
	
	МассивУзловРезультат = Новый Массив;
	
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("ОбъектМетаданных", Объект.Метаданные());
	ДополнительныеПараметры.Вставить("ЭтоРегистр", ОбщегоНазначения.ЭтоРегистр(ДополнительныеПараметры.ОбъектМетаданных));
	ВыполнитьПравилаРегистрацииОбъектовДляПланаОбмена(МассивУзловРезультат, Объект, ИмяПланаОбмена, ДополнительныеПараметры);
	
	Возврат МассивУзловРезультат;
	
КонецФункции

// Определяет признак авторегистрации объекта метаданных в составе плана обмена.
//
// Параметры:
//   ОбъектМетаданных - ОбъектМетаданных - объект, для которого требуется получить признак авторегистрации. 
//   ИмяПланаОбмена - Строка - имя плана обмена, как оно задано в конфигураторе, в состав которого входит
//                          объект метаданных.
//
// Возвращаемое значение:
//   Булево - признак наличия авторегистрации в плане обмена:
//           * Истина - объект метаданных имеет признак авторегистрации "Разрешена" в составе плана обмена;
//           * Ложь   - объект метаданных имеет признак авторегистрации "Запрещена" в составе плана обмена
//                      или объект метаданных не входит в состав плана обмена.
//
Функция АвтоРегистрацияРазрешена(ОбъектМетаданных, ИмяПланаОбмена) Экспорт
	
	Возврат ОбменДаннымиПовтИсп.АвтоРегистрацияРазрешена(ИмяПланаОбмена, ОбъектМетаданных.ПолноеИмя());
	
КонецФункции

// Проверяет наличие запрета загрузки элемента данных.
//  Для работы функции требуется настройка процедуры ДанныеДляПроверкиЗапретаИзменения
// модуля ДатыЗапретаИзмененияПереопределяемый.
//
// Параметры:
//  Данные     - Произвольный - СправочникОбъект.<Имя>,
//                        ДокументОбъект.<Имя>,
//                        ПланВидовХарактеристикОбъект.<Имя>,
//                        ПланСчетовОбъект.<Имя>,
//                        ПланВидовРасчетаОбъект.<Имя>,
//                        БизнесПроцессОбъект.<Имя>,
//                        ЗадачаОбъект.<Имя>,
//                        ПланОбменаОбъект.<Имя>,
//                        УдалениеОбъекта - объект данных.
//                        РегистрСведенийНаборЗаписей.<Имя>,
//                        РегистрНакопленияНаборЗаписей.<Имя>,
//                        РегистрБухгалтерииНаборЗаписей.<Имя>,
//                        РегистрРасчетаНаборЗаписей.<Имя> - набор записей.
//
//  УзелПланаОбмена     - ПланыОбменаОбъект - узел,
//                        для которого будет выполнена проверка.
//
// Возвращаемое значение:
//  Булево - если Истина, загрузка запрещена.
//
Функция ЗагрузкаЗапрещена(Данные, Знач УзелПланаОбмена) Экспорт
	
	ЭтоУдалениеОбъекта = (ТипЗнч(Данные) = Тип("УдалениеОбъекта"));
	
	Если Не ЭтоУдалениеОбъекта
		И Данные.ДополнительныеСвойства.Свойство("НайденЗапретЗагрузкиДанных") Тогда
		Возврат Истина;
	КонецЕсли;
	
	ПолучениеЭлемента = ПолучениеЭлементаДанных.Авто;
	ПроверитьНаличиеЗапретаЗагрузкиПоДате(Данные, ПолучениеЭлемента, УзелПланаОбмена);
	
	Возврат ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции для вызова из других библиотек.

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковЗагрузкиДанных.
Процедура ПриРегистрацииОбработчиковЗагрузкиДанных(ТаблицаОбработчиков) Экспорт
	
	Для Каждого ИмяПланаОбмена Из ОбменДаннымиПовтИсп.ПланыОбменаБСП() Цикл
		
		СтрокаОбработчика = ТаблицаОбработчиков.Добавить();
		СтрокаОбработчика.ОбъектМетаданных      = Метаданные.ПланыОбмена[ИмяПланаОбмена];
		СтрокаОбработчика.Обработчик            = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСобытия");
		СтрокаОбработчика.ПослеЗагрузкиОбъекта = Истина;
		
	КонецЦикла;
		
КонецПроцедуры

// Выполняет обработчики после загрузки объекта.
//
// Параметры:
//  Контейнер - ОбработкаОбъект.ВыгрузкаЗагрузкаДанныхМенеджерКонтейнера - менеджер
//		контейнера, используемый в процессе выгрузи данных. Подробнее см. комментарий
//		к программному интерфейсу обработки ВыгрузкаЗагрузкаДанныхМенеджерКонтейнера.
//  Объект - Произвольный - объект загружаемых данных.
//  Артефакты - Массив из ОбъектXDTO - массив артефактов (объектов XDTO).
//
Процедура ПослеЗагрузкиОбъекта(Контейнер, Объект, Артефакты) Экспорт
	
	СписокПлановОбмена = ОбменДаннымиПовтИсп.ПланыОбменаБСП();
	Если СписокПлановОбмена.Найти(Объект.Метаданные().Имя) <> Неопределено
		И Не Объект.ЭтотУзел Тогда
		
		Запись = РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.СоздатьМенеджерЗаписи();
		Запись.УзелИнформационнойБазы = Объект.Ссылка;
		Запись.СинхронизацияНедоступна = Истина;
		Запись.НастройкаЗавершена = Истина;
		Запись.Записать(Истина);
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

// Процедура предназначена для определения вида отправки выгружаемого элемента данных.
// Вызывается из обработчиков планов обмена: ПриОтправкеДанныхГлавному(), ПриОтправкеДанныхПодчиненному().
//
// Параметры:
//   ЭлементДанных - КонстантаМенеджерЗначения
//                 - СправочникОбъект
//                 - ДокументОбъект
//                 - РегистрСведенийНаборЗаписей
//                 - и т.п. -
//                   элемент данных.
//   ОтправкаЭлемента - ОтправкаЭлементаДанных - см. описание параметра "ОтправкаЭлемента" в синтаксис помощнике
//                      для методов ПриОтправкеДанныхГлавному() и ПриОтправкеДанныхПодчиненному().
//   СозданиеНачальногоОбраза - Булево - признак вызова процедуры при создании начального образа РИБ.
//   Получатель - ПланОбменаСсылка
//              - Неопределено - узел получателя.
//   Анализ - Булево - признак вызова процедуры при анализе.
//
Процедура ПриОтправкеДанныхКорреспонденту(ЭлементДанных,
										ОтправкаЭлемента,
										Знач СозданиеНачальногоОбраза = Ложь,
										Знач Получатель = Неопределено,
										Знач Анализ = Истина) Экспорт
	
	Если Получатель = Неопределено Тогда
		
		//
		
	ИначеЕсли ОтправкаЭлемента = ОтправкаЭлементаДанных.Удалить
		ИЛИ ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда
		
		// Стандартную обработку не переопределяем.
		
	ИначеЕсли ОбменДаннымиПовтИсп.ЭтоУзелОбменаДаннымиБСП(Получатель.Ссылка) Тогда
		
		ПриОтправкеДанных(ЭлементДанных, ОтправкаЭлемента, Получатель.Ссылка, СозданиеНачальногоОбраза, Анализ);
		
	КонецЕсли;
	
	Если Анализ Тогда
		Возврат;
	КонецЕсли;
	
	// Фиксируем выгруженные предопределенные данные (только для РИБ).
	Если Не СозданиеНачальногоОбраза
		И ОтправкаЭлемента <> ОтправкаЭлементаДанных.Игнорировать
		И ОбменДаннымиПовтИсп.ЭтоУзелРаспределеннойИнформационнойБазы(Получатель.Ссылка)
		И ТипЗнч(ЭлементДанных) <> Тип("УдалениеОбъекта") Тогда
		
		ОбъектМетаданных = ЭлементДанных.Метаданные();
		
		Если ОбщегоНазначения.ЭтоСправочник(ОбъектМетаданных)
			ИЛИ ОбщегоНазначения.ЭтоПланВидовХарактеристик(ОбъектМетаданных)
			ИЛИ ОбщегоНазначения.ЭтоПланСчетов(ОбъектМетаданных)
			ИЛИ ОбщегоНазначения.ЭтоПланВидовРасчета(ОбъектМетаданных) Тогда
			
			Если ЭлементДанных.Предопределенный Тогда
				
				ОбменДаннымиСлужебный.ДополнитьПриоритетныеДанныеОбмена(ЭлементДанных.Ссылка);
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Процедура является обработчиком одноименного события, возникающего при обмене данными в распределенной
// информационной базе.
//
// Параметры:
//   см. описание обработчика события ПриПолученииДанныхОтГлавного() в синтакс-помощнике.
// 
Процедура ПриПолученииДанныхОтГлавногоВНачале(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель) Экспорт
	
	Если ОбменДаннымиСлужебный.РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском(
			"ЗагрузкаПараметровРаботыПрограммы") Тогда
		
		// В режиме загрузки параметров работы программы игнорируем получение всех данных.
		ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать;
		
	Иначе
		
		Если ТипЗнч(ЭлементДанных) = Тип("КонстантаМенеджерЗначения.ДанныеДляОтложенногоОбновления") Тогда
			ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать;
			ОбменДаннымиСервер.ОбработатьДанныеДляОбновленияВПодчиненномУзле(ЭлементДанных);
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Процедура предназначена для выполнения проверок на наличие коллизий запрета загрузки и изменения данных.
// Вызывается из обработчика плана обмена: ПриПолученииДанныхОтГлавного.
//
// Параметры:
//   см. описание обработчика события ПриПолученииДанныхОтГлавного() в синтакс-помощнике.
// 
Процедура ПриПолученииДанныхОтГлавногоВКонце(ЭлементДанных, ПолучениеЭлемента, Знач Отправитель) Экспорт
	
	// Проверка на запрет загрузки по дате запрета.
	ПроверитьНаличиеЗапретаЗагрузкиПоДате(ЭлементДанных, ПолучениеЭлемента, Отправитель);
	
	Если ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать Тогда
		Возврат;
	КонецЕсли;
	
	// Проверка на коллизию изменения данных.
	ПроверитьКоллизиюИзмененийДанных(ЭлементДанных, ПолучениеЭлемента, Отправитель, Истина);
	
КонецПроцедуры

// Процедура предназначена для выполнения проверок на наличие коллизий запрета загрузки и изменения данных.
// Вызывается из обработчика плана обмена: ПриПолученииДанныхОтПодчиненного.
//
// Параметры:
//   см. описание обработчика события ПриПолученииДанныхОтПодчиненного() в синтакс-помощнике.
// 
Процедура ПриПолученииДанныхОтПодчиненногоВКонце(ЭлементДанных, ПолучениеЭлемента, Знач Отправитель) Экспорт
	
	// Проверка на запрет загрузки по дате запрета.
	ПроверитьНаличиеЗапретаЗагрузкиПоДате(ЭлементДанных, ПолучениеЭлемента, Отправитель);
	
	Если ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать Тогда
		Возврат;
	КонецЕсли;
	
	// Проверка на коллизию изменения данных.
	ПроверитьКоллизиюИзмененийДанных(ЭлементДанных, ПолучениеЭлемента, Отправитель, Ложь);
	
КонецПроцедуры

// Регистрирует изменение одного элемента данных для последующей отправки в адрес узла-получателя.
// Элемент данных будет зарегистрирован только в том случае, если он соответствует фильтрам правил регистрации 
// объектов,установленным в свойствах узла-получателя.
// Элементы данных, которые выгружаются при необходимости, регистрируются безусловно.
// Объект УдалениеОбъекта регистрируется безусловно.
//
// Параметры:
//     Получатель - ПланОбменаСсылка          - узел плана обмена, для которого выполняется регистрация изменений
//                                              данных.
//     Данные     - СправочникОбъект
//                - ДокументОбъект
//                - Произвольный
//                - УдалениеОбъекта - объект, представляющий данные,
//                  хранимые в базе данных, такой как документ, элемент справочника, счет бухгалтерского учета, менеджер
//                  записи константы, набор записей регистра и т. п.
//     ПроверятьРазрешениеВыгрузки - Булево   - флаг. Если установить в Ложь, то дополнительная проверка
//                                              на соответствие общим настройкам узла при регистрации производится не
//                                              будет.
//
Процедура ЗарегистрироватьИзмененияДанных(Знач Получатель, Знач Данные, Знач ПроверятьРазрешениеВыгрузки=Истина) Экспорт
	
	Если ТипЗнч(Данные) = Тип("УдалениеОбъекта") Тогда
		// Удаление объекта регистрируем безусловно.
		ПланыОбмена.ЗарегистрироватьИзменения(Получатель, Данные);
		
	Иначе
		РежимВыгрузкиОбъекта = ОбменДаннымиПовтИсп.РежимВыгрузкиОбъекта(Данные.Метаданные().ПолноеИмя(), Получатель);
		
		Если РежимВыгрузкиОбъекта = Перечисления.РежимыВыгрузкиОбъектовОбмена.ВыгружатьПриНеобходимости
			И ОбщегоНазначения.ЗначениеСсылочногоТипа(Данные) Тогда
			
			ЭтоНовыйОбъект = Данные.Пустая();
			
			Если ЭтоНовыйОбъект Тогда
				ВызватьИсключение НСтр("ru = 'Регистрация незаписанных объектов, выгружаемых по ссылке, не поддерживается.'");
			КонецЕсли;
			
			НачатьТранзакцию();
			Попытка
				// Выполняем регистрацию данных на узле-получателе.
				ПланыОбмена.ЗарегистрироватьИзменения(Получатель, Данные);
				
				// Для данных, выгружаемых по ссылке, дополнительно заносим сведения в фильтр разрешенных к выгрузке объектов.
				// Это нужно для того, чтобы данные прошли фильтр при выгрузке и были выгружены в сообщение обмена.
				Если ОбменДаннымиСервер.ЭтоПланОбменаXDTO(Получатель) Тогда
					ОбменДаннымиXDTOСервер.ДобавитьОбъектВФильтрРазрешенныхОбъектов(Данные.Ссылка, Получатель);
				Иначе
					РегистрыСведений.СоответствияОбъектовИнформационныхБаз.ДобавитьОбъектВФильтрРазрешенныхОбъектов(Данные.Ссылка, Получатель);
				КонецЕсли;
				
				ЗафиксироватьТранзакцию();
			Исключение
				ОтменитьТранзакцию();
				ВызватьИсключение;
			КонецПопытки;
			
		ИначеЕсли Не ПроверятьРазрешениеВыгрузки Тогда
			// Регистрируем безусловно
			ПланыОбмена.ЗарегистрироватьИзменения(Получатель, Данные);
			
		ИначеЕсли ВыгрузкаОбъектаРазрешена(Получатель, Данные) Тогда
			// Регистрируем, только если объект удовлетворяет общим ограничениям.
			ПланыОбмена.ЗарегистрироватьИзменения(Получатель, Данные);
			
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

Процедура УстановитьЗначенияОтборовНаУзле(УзелПланаОбмена, Настройки) Экспорт
	
	УстановитьЗначенияНаУзле(УзелПланаОбмена, Настройки);
	
КонецПроцедуры

Процедура УстановитьЗначенияПоУмолчаниюНаУзле(УзелПланаОбмена, Настройки) Экспорт
	
	УстановитьЗначенияНаУзле(УзелПланаОбмена, Настройки);
	
КонецПроцедуры

// Создает и записывает версию объекта в информационную базу.
//
// Параметры:
//  Объект - записываемый объект ИБ.
//  СсылкаСуществует - Булево - признак наличия объекта по ссылке в информационной базе.
//  СведенияОВерсииОбъекта - Структура:
//    * АвторВерсии - Пользователь, УзелПланаОбмена - источник версии.
//        Необязательный, значение по умолчанию Неопределено.
//    * ТипВерсииОбъекта - Строка - тип создаваемой версии.
//        Необязательный, значение по умолчанию "ИзмененоПользователем".
//    * ПредупреждениеСинхронизации - Строка - предупреждение синхронизации к создаваемой версии.
//        Необязательный, значение по умолчанию "".
//
Процедура ПриСозданииВерсииОбъекта(Объект, СведенияОВерсииОбъекта, СсылкаСуществует, Отправитель) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ВерсионированиеОбъектов") Тогда
		
		СведенияОНовойВерсииОбъекта = Новый Структура;
		СведенияОНовойВерсииОбъекта.Вставить("АвторВерсии", Неопределено);
		СведенияОНовойВерсииОбъекта.Вставить("ТипВерсииОбъекта", "ИзмененоПользователем");
		СведенияОНовойВерсииОбъекта.Вставить("Комментарий", "");
		СведенияОНовойВерсииОбъекта.Вставить("ПредупреждениеСинхронизации", "");
		ЗаполнитьЗначенияСвойств(СведенияОНовойВерсииОбъекта, СведенияОВерсииОбъекта);
		
		МодульВерсионированиеОбъектов = ОбщегоНазначения.ОбщийМодуль("ВерсионированиеОбъектов");
		МодульВерсионированиеОбъектов.СоздатьВерсиюОбъектаПоОбменуДанными(Объект, СведенияОНовойВерсииОбъекта, СсылкаСуществует, Отправитель);
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

#Область ОбработчикиПодписокНаСобытия

Процедура ЗарегистрироватьИзмененияФильтровОграниченияМиграцииДанных(Источник, Отказ) Экспорт
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
	Если Источник.ЭтоНовый() Тогда
		Возврат;
	ИначеЕсли Источник.ДополнительныеСвойства.Свойство("ПолучениеСообщенияОбмена") Тогда
		Возврат; // Запись узла при получении сообщения обмена (универсальный обмен данными).
	ИначеЕсли Не ОбменДаннымиПовтИсп.ЭтоУзелОбменаДаннымиБСП(Источник.Ссылка) Тогда
		Возврат;
	ИначеЕсли Источник.ЭтотУзел Тогда
		Возврат;
	КонецЕсли;
	
	ИсточникСсылка = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Источник.Ссылка, "НомерОтправленного, НомерПринятого");
	
	Если ИсточникСсылка.НомерОтправленного <> Источник.НомерОтправленного Тогда
		Возврат; // Запись узла при отправке сообщения обмена.
	ИначеЕсли ИсточникСсылка.НомерПринятого <> Источник.НомерПринятого Тогда
		Возврат; // Запись узла при получении сообщения обмена.
	КонецЕсли;
	
	ПараметрыПроверкиУзла = Новый Структура;
	ПараметрыПроверкиУзла.Вставить("УзелМодифицирован", Ложь);
	ПараметрыПроверкиУзла.Вставить("РеквизитыСсылочногоТипаУзлаПланаОбмена", Неопределено);
	
	УзелПланаОбменаМодифицированПоСсылочнымРеквизитам(Источник, ПараметрыПроверкиУзла);
	
	Если ПараметрыПроверкиУзла.УзелМодифицирован
		И ПараметрыПроверкиУзла.РеквизитыСсылочногоТипаУзлаПланаОбмена <> Неопределено Тогда
		
		Источник.ДополнительныеСвойства.Вставить("ТаблицаРеквизитовУзла", ПараметрыПроверкиУзла.РеквизитыСсылочногоТипаУзлаПланаОбмена);
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ПроверитьИзменениеФильтровОграниченияМиграцииДанныхПриЗаписи(Источник, Отказ) Экспорт
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
	Если Не ОбменДаннымиПовтИсп.ЭтоУзелОбменаДаннымиБСП(Источник.Ссылка) Тогда
		Возврат;
	КонецЕсли;
	
	ЗарегистрированныеКВыгрузкеОбъекты = Неопределено;
	Если Источник.ДополнительныеСвойства.Свойство("ЗарегистрированныеКВыгрузкеОбъекты", ЗарегистрированныеКВыгрузкеОбъекты) Тогда
		
		ОбменДаннымиСлужебный.ОбновитьКэшМеханизмаРегистрацииОбъектов();
		
		Для Каждого ЭлементНабор Из ЗарегистрированныеКВыгрузкеОбъекты Цикл
			
			Если ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(ЭлементНабор.Ключ) Тогда
				
				ПараметрыПР = ПараметрыПакетнойРегистрации();
				
				ВыполнитьПакетнуюРегистрациюДляУзла(Источник.Ссылка, ЭлементНабор.Значение, ПараметрыПР);
					
				Если ПараметрыПР.ЕстьПРО_БезПакетнойРегистрации Тогда
					Для Каждого Ссылка Из ПараметрыПР.СсылкиНеПоФильтруПакетнойРегистрации Цикл
						Если Не ВыгрузкаОбъектаРазрешена(Источник.Ссылка, Ссылка) Тогда
							ПланыОбмена.УдалитьРегистрациюИзменений(Источник.Ссылка, Ссылка);
						КонецЕсли;
					КонецЦикла;
				Иначе
					Для Каждого Ссылка Из ПараметрыПР.СсылкиНеПоФильтруПакетнойРегистрации Цикл
						ПланыОбмена.УдалитьРегистрациюИзменений(Источник.Ссылка, Ссылка);
					КонецЦикла;
				КонецЕсли;
					
			ИначеЕсли ОбщегоНазначения.ЭтоКонстанта(ЭлементНабор.Ключ) Тогда
				
				Объект = ЭлементНабор.Значение;
				Если Не ВыгрузкаОбъектаРазрешена(Источник.Ссылка, Объект) Тогда
					ПланыОбмена.УдалитьРегистрациюИзменений(Источник.Ссылка, Объект);
				КонецЕсли;
				Объект = Неопределено;
				
			Иначе
				
				МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ЭлементНабор.Ключ.ПолноеИмя());
				
				ТаблицаОтборы = ЭлементНабор.Значение; // ТаблицаЗначений
				Пока ТаблицаОтборы.Количество() > 0 Цикл
					
					Объект = МенеджерОбъекта.СоздатьНаборЗаписей();
					Для Каждого ЭлементОтбора Из ТаблицаОтборы.Колонки Цикл
						ОбменДаннымиСлужебный.УстановитьЗначениеЭлементаОтбора(
							Объект.Отбор, ЭлементОтбора.Имя, ТаблицаОтборы[0][ЭлементОтбора.Имя]);
					КонецЦикла;
					Объект.Прочитать();
					
					Если Не ВыгрузкаОбъектаРазрешена(Источник.Ссылка, Объект) Тогда
						ПланыОбмена.УдалитьРегистрациюИзменений(Источник.Ссылка, Объект);
					КонецЕсли;
					Объект = Неопределено;
					ТаблицаОтборы.Удалить(0);
					
				КонецЦикла;
				
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЕсли;
	
	ТаблицаРеквизитовСсылочногоТипа = Неопределено;
	Если Источник.ДополнительныеСвойства.Свойство("ТаблицаРеквизитовУзла", ТаблицаРеквизитовСсылочногоТипа) Тогда
		
		// Выполняем регистрацию выбранных объектов ссылочного типа на текущем узле без использования ПРО.
		ВыполнитьРегистрациюОбъектовСсылочногоТипаПоСвойствамУзла(Источник, ТаблицаРеквизитовСсылочногоТипа);
		
		// Обновляем повторно используемые значения механизма.
		ОбменДаннымиСлужебный.СброситьКэшМеханизмаРегистрацииОбъектов();
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ВключитьИспользованиеПланаОбмена(Источник, Отказ) Экспорт
	
	// Проверка значения свойства ОбменДанными.Загрузка отсутствует по причине того, что в расположенным ниже коде,
	// реализована логика, которая должна выполняться в том числе при установке этого свойства равным Истина
	// (на стороне кода, который выполняет попытку записи в данный план обмена).
	
	Если Источник.ЭтоНовый() И ОбменДаннымиПовтИсп.ЭтоУзелРазделенногоОбменаДаннымиБСП(Источник.Ссылка) Тогда
		
		// Кэш открытых сеансов для МРО стал неактуальным.
		ОбменДаннымиСлужебный.СброситьКэшМеханизмаРегистрацииОбъектов();
		
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//   Источник - ПланОбменаОбъект - узел плана обмена.
//   Отказ - Булево - Истина, в случае отказа от выполнения операции.
//
Процедура ОтключитьИспользованиеПланаОбмена(Источник, Отказ) Экспорт
	
	// Проверка значения свойства ОбменДанными.Загрузка отсутствует по причине того, что в расположенным ниже коде,
	// реализована логика, которая должна выполняться в том числе при установке этого свойства равным Истина
	// (на стороне кода, который выполняет попытку удаления узла данного плана обмена).
	
	Если ОбменДаннымиПовтИсп.ЭтоУзелРазделенногоОбменаДаннымиБСП(Источник.Ссылка) Тогда
		
		// Кэш открытых сеансов для МРО стал неактуальным.
		ОбменДаннымиСлужебный.СброситьКэшМеханизмаРегистрацииОбъектов();
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ПроверитьВозможностьИзмененияНастроекОбменаДанными(Источник, Отказ) Экспорт
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
	Если Не ОбменДаннымиПовтИсп.ЭтоУзелОбменаДаннымиБСП(Источник.Ссылка) Тогда
		Возврат;
	КонецЕсли;
	
	ИсключаемыеСвойства = Новый Массив;
	ИсключаемыеСвойства.Добавить("НомерОтправленного");
	ИсключаемыеСвойства.Добавить("НомерПринятого");
	ИсключаемыеСвойства.Добавить("ПометкаУдаления");
	ИсключаемыеСвойства.Добавить("Код");
	ИсключаемыеСвойства.Добавить("Наименование");
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		ПолноеИмяМетаданных = Источник.Метаданные().ПолноеИмя();
		
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		
		РазделительОсновныхДанных        = МодульРаботаВМоделиСервиса.РазделительОсновныхДанных();
		РазделительВспомогательныхДанных = МодульРаботаВМоделиСервиса.РазделительВспомогательныхДанных();
		
		Если МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(ПолноеИмяМетаданных, РазделительОсновныхДанных) Тогда
			ИсключаемыеСвойства.Добавить(РазделительОсновныхДанных);
		КонецЕсли;
		
		Если МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(ПолноеИмяМетаданных, РазделительВспомогательныхДанных) Тогда
			ИсключаемыеСвойства.Добавить(РазделительВспомогательныхДанных);
		КонецЕсли;
		
	КонецЕсли;
	
	Если Источник.ДополнительныеСвойства.Свойство("ОтложеннаяЗаписьУзла") 
		Или (Не Источник.ДополнительныеСвойства.Свойство("ПолучениеСообщенияОбмена")
		И Не Источник.ЭтоНовый()
		И Не Источник.ЭтотУзел
		И ДанныеРазличаются(Источник, Источник.Ссылка.ПолучитьОбъект(), , СтрСоединить(ИсключаемыеСвойства, ","))
		И ОбменДаннымиСлужебный.ИзмененияЗарегистрированы(Источник.Ссылка)) Тогда
		
		СохранитьРазрешенныеКВыгрузкеОбъекты(Источник);
		
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		СеансЗапущенБезРазделителей = МодульРаботаВМоделиСервиса.СеансЗапущенБезРазделителей();
	Иначе
		СеансЗапущенБезРазделителей = Истина;
	КонецЕсли;
	
	// Код и наименование узла в сервисе менять нельзя.
	Если ОбщегоНазначения.РазделениеВключено()
		И НЕ СеансЗапущенБезРазделителей
		И Не Источник.ЭтоНовый()
		И ДанныеРазличаются(Источник, Источник.Ссылка.ПолучитьОбъект(), "Код, Наименование") Тогда
		
		ВызватьИсключение НСтр("ru = 'Изменение наименования и кода синхронизации данных недопустимо.'");
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ОтключитьАвтоматическуюСинхронизациюДанныхПриЗаписи(Источник, Отказ, Замещение) Экспорт
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
		МодульАвтономнаяРабота = ОбщегоНазначения.ОбщийМодуль("АвтономнаяРабота");
		МодульАвтономнаяРабота.ОтключитьАвтоматическуюСинхронизациюДанныхСПриложениемВИнтернете(Источник);
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//   УзелСсылка - ПланОбменаСсылка
//   ПолноеИмяОбъектаМетаданных - Строка
//   
// Возвращаемое значение:
//   ТаблицаЗначений - выгрузка из таблицы изменений объекта:
//     * Ссылка - ЛюбаяСсылка - ссылка на объект.
//     * Узел - ПланОбменаСсылка - узел плана обмена.
//     * Регистратор - ДокументСсылка - регистратор набора записей (опционально).
//     * <ВедущиеИзмененияРегистров> - Произвольный
//
Функция ЗарегистрированныеДанныеОдногоТипа(УзелСсылка, ПолноеИмяОбъектаМетаданных)
	
	Запрос = Новый Запрос(
	"ВЫБРАТЬ
	|	*
	|ИЗ
	|	#ТаблицаИзменения КАК ТаблицаИзменения
	|ГДЕ
	|	ТаблицаИзменения.Узел = &Узел");
	Запрос.УстановитьПараметр("Узел", УзелСсылка);
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "#ТаблицаИзменения", ПолноеИмяОбъектаМетаданных + ".Изменения");
		
	Возврат Запрос.Выполнить().Выгрузить();
	
КонецФункции

// Возвращаемое значение:
//   ТаблицаЗначений:
//     * Ссылка - ЛюбаяСсылка - ссылка на зарегистрированный объект.
//
Функция ЗарегистрированныеДанныеОдногоСсылочногоТипа(УзелСсылка, ПолноеИмяОбъектаМетаданных)
	
	Запрос = Новый Запрос(
	"ВЫБРАТЬ
	|	ТаблицаОбъект.Ссылка КАК Ссылка
	|ИЗ
	|	#ТаблицаИзменения КАК ТаблицаИзменения
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ #ТаблицаОбъект КАК ТаблицаОбъект
	|		ПО ТаблицаИзменения.Ссылка = ТаблицаОбъект.Ссылка
	|ГДЕ
	|	ТаблицаИзменения.Узел = &Узел");
	Запрос.УстановитьПараметр("Узел", УзелСсылка);
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "#ТаблицаИзменения", ПолноеИмяОбъектаМетаданных + ".Изменения");
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "#ТаблицаОбъект", ПолноеИмяОбъектаМетаданных);
	
	Возврат Запрос.Выполнить().Выгрузить();
	
КонецФункции

Процедура СохранитьРазрешенныеКВыгрузкеОбъекты(УзелОбъект)
	
	УстановитьПривилегированныйРежим(Истина);
	
	ЗарегистрированныеДанные = Новый Соответствие;
	
	СоставПланаОбмена = УзелОбъект.Метаданные().Состав;
	
	Для Каждого ЭлементСостава Из СоставПланаОбмена Цикл
		
		Если ЭлементСостава.Авторегистрация = АвтоРегистрацияИзменений.Разрешить Тогда
			Продолжить;
		КонецЕсли;
		
		МетаданныеЭлемента = ЭлементСостава.Метаданные;
		ПолноеИмяОбъектаМетаданных = МетаданныеЭлемента.ПолноеИмя();
		
		Если ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(МетаданныеЭлемента) Тогда
			
			КоллекцияСсылок = Новый Массив;
			
			НаборДанных = ЗарегистрированныеДанныеОдногоСсылочногоТипа(УзелОбъект.Ссылка, ПолноеИмяОбъектаМетаданных);
			
			МассивСсылок = НаборДанных.ВыгрузитьКолонку("Ссылка");
			ПараметрыПР = ПараметрыПакетнойРегистрации();
			
			ВыполнитьПакетнуюРегистрациюДляУзла(УзелОбъект.Ссылка, МассивСсылок, ПараметрыПР);
				
			Для Каждого Ссылка Из ПараметрыПР.СсылкиПоФильтруПакетнойРегистрации Цикл
				КоллекцияСсылок.Добавить(Ссылка);
			КонецЦикла;
			
			Если ПараметрыПР.ЕстьПРО_БезПакетнойРегистрации Тогда
				Для Каждого Ссылка Из ПараметрыПР.СсылкиНеПоФильтруПакетнойРегистрации Цикл
					Если ВыгрузкаОбъектаРазрешена(УзелОбъект.Ссылка, Ссылка) Тогда
						КоллекцияСсылок.Добавить(Ссылка);
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
			
			ЗарегистрированныеДанные[МетаданныеЭлемента] = КоллекцияСсылок;
			
		ИначеЕсли ОбщегоНазначения.ЭтоКонстанта(МетаданныеЭлемента) Тогда
			
			МенеджерЗначенияКонстанты = Константы[МетаданныеЭлемента.Имя].СоздатьМенеджерЗначения();
			Если ВыгрузкаОбъектаРазрешена(УзелОбъект.Ссылка, МенеджерЗначенияКонстанты) Тогда
				ЗарегистрированныеДанные[МетаданныеЭлемента] = МенеджерЗначенияКонстанты;
			КонецЕсли;
			
		Иначе // Регистр или последовательность.
		
			ТаблицаОтборы = Новый ТаблицаЗначений;
			
			МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмяОбъектаМетаданных);
			
			НаборДанных = ЗарегистрированныеДанныеОдногоТипа(УзелОбъект.Ссылка, ПолноеИмяОбъектаМетаданных);
			
			НаборЗаписей = МенеджерОбъекта.СоздатьНаборЗаписей(); // РегистрСведенийНаборЗаписей, и т.п.
			Для Каждого ЭлементОтбора Из НаборЗаписей.Отбор Цикл
				Если НаборДанных.Колонки.Найти(ЭлементОтбора.Имя) <> Неопределено Тогда
					ТаблицаОтборы.Колонки.Добавить(ЭлементОтбора.Имя);
				КонецЕсли;
			КонецЦикла;
			
			Для Каждого СтрокаДанные Из НаборДанных Цикл
				
				НаборЗаписей = МенеджерОбъекта.СоздатьНаборЗаписей(); // РегистрСведенийНаборЗаписей, и т.п.
				Для Каждого ЭлементОтбора Из ТаблицаОтборы.Колонки Цикл
					ОбменДаннымиСлужебный.УстановитьЗначениеЭлементаОтбора(
						НаборЗаписей.Отбор, ЭлементОтбора.Имя, СтрокаДанные[ЭлементОтбора.Имя]);
				КонецЦикла;
				
				НаборЗаписей.Прочитать();
				
				Если ВыгрузкаОбъектаРазрешена(УзелОбъект.Ссылка, НаборЗаписей) Тогда
					СтруктураОтбора = ТаблицаОтборы.Добавить();
					ЗаполнитьЗначенияСвойств(СтруктураОтбора, СтрокаДанные);
				КонецЕсли;
				
			КонецЦикла;
			
			ЗарегистрированныеДанные[МетаданныеЭлемента] = ТаблицаОтборы;
			
		КонецЕсли;
		
	КонецЦикла;
	
	УзелОбъект.ДополнительныеСвойства.Вставить("ЗарегистрированныеКВыгрузкеОбъекты", ЗарегистрированныеДанные);
	
КонецПроцедуры

Функция ВыгрузкаОбъектаРазрешена(УзелОбмена, Объект)
	
	Если ОбщегоНазначения.ЗначениеСсылочногоТипа(Объект) Тогда
		Возврат ОбменДаннымиСервер.ВыгрузкаСсылкиРазрешена(УзелОбмена, Объект);
	КонецЕсли;
	
	Отправка = ОтправкаЭлементаДанных.Авто;
	ПриОтправкеДанныхКорреспонденту(Объект, Отправка, , УзелОбмена);
	Возврат Отправка = ОтправкаЭлементаДанных.Авто;
КонецФункции

Процедура ОтменитьОтправкуДанныхУзлаВРаспределеннойИнформационнойБазе(Источник, ЭлементДанных, Игнорировать) Экспорт
	
	Если Не ОбменДаннымиПовтИсп.ЭтоУзелОбменаДаннымиБСП(Источник.Ссылка) Тогда
		Возврат;
	КонецЕсли;
	
	Если Не ЭлементДанных.ЭтотУзел Тогда
		Если ОбщегоНазначения.РазделениеВключено() Тогда
			// При отправке данных узла в разделенном режиме необходимо обнулять значения разделителей.
			// В противном случае при загрузке в неразделенный АРМ будет происходить попытка записи узла в неинициализированную
			// область данных с указанным значением разделителя, что приведет к ошибке отсутствия в ней узла с признаком "ЭтотУзел".
			МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
			Если МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(Источник.Метаданные().ПолноеИмя(),
				МодульРаботаВМоделиСервиса.РазделительОсновныхДанных()) Тогда
				ЭлементДанных[МодульРаботаВМоделиСервиса.РазделительОсновныхДанных()] = 0;
			КонецЕсли;
			Если МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(Источник.Метаданные().ПолноеИмя(),
				МодульРаботаВМоделиСервиса.РазделительВспомогательныхДанных()) Тогда
				ЭлементДанных[МодульРаботаВМоделиСервиса.РазделительВспомогательныхДанных()] = 0;
			КонецЕсли;
		КонецЕсли;
		
		Возврат;
	КонецЕсли;
	
	Игнорировать = Истина;
	
КонецПроцедуры

Процедура ЗарегистрироватьИзмененияОбщихДанныхУзлов(Источник, Отказ) Экспорт
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
	Если Источник.ЭтоНовый() Тогда
		Возврат;
	ИначеЕсли Источник.ДополнительныеСвойства.Свойство("ПолучениеСообщенияОбмена") Тогда
		Возврат; // Запись узла при получении сообщения обмена (универсальный обмен данными).
	ИначеЕсли Не ОбменДаннымиПовтИсп.ЭтоУзелРазделенногоОбменаДаннымиБСП(Источник.Ссылка) Тогда
		Возврат;
	ИначеЕсли Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		Возврат;
	КонецЕсли;
	
	ОбщиеДанныеУзлов = ОбменДаннымиПовтИсп.ОбщиеДанныеУзлов(Источник.Ссылка);
	
	Если ПустаяСтрока(ОбщиеДанныеУзлов) Тогда
		Возврат;
	КонецЕсли;
	
	Если Источник.ЭтотУзел Тогда
		Возврат;
	КонецЕсли;
	
	Если ДанныеРазличаются(Источник, Источник.Ссылка.ПолучитьОбъект(), ОбщиеДанныеУзлов) Тогда
		
		РегистрыСведений.ИзмененияОбщихДанныхУзлов.ЗарегистрироватьИзменения(Источник.Ссылка);
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ОчиститьСсылкиНаУзелИнформационнойБазы(Источник, Отказ) Экспорт
	
	// Проверка значения свойства ОбменДанными.Загрузка отсутствует по причине того, что в расположенным ниже коде,
	// реализована логика, которая должна выполняться в том числе при установке этого свойства равным Истина
	// (на стороне кода, который выполняет попытку удаления узла данного плана обмена).
	
	Если Не ОбменДаннымиПовтИсп.ЭтоУзелОбменаДаннымиБСП(Источник.Ссылка) Тогда
		Возврат;
	КонецЕсли;
	
	Справочники.СценарииОбменовДанными.ОчиститьСсылкиНаУзелИнформационнойБазы(Источник.Ссылка);
	
	Если ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		
		Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.ОчередьЗаданий")
			И Не Источник.ДополнительныеСвойства.Свойство("ЭтоГлавныйУзелАРМ") Тогда
			
			МодульОчередьЗаданий = ОбщегоНазначения.ОбщийМодуль("ОчередьЗаданий");
			МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
			
			КлючЗадания = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Обмен данными с внешней системой (%1)'"),
				Источник.Код);
				
			Отбор = Новый Структура;
			Отбор.Вставить("ОбластьДанных", МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса());
			Отбор.Вставить("Ключ",          КлючЗадания);
			
			ТаблицаЗадания = МодульОчередьЗаданий.ПолучитьЗадания(Отбор);
			Для Каждого СтрокаЗадания Из ТаблицаЗадания Цикл
				МодульОчередьЗаданий.УдалитьЗадание(СтрокаЗадания.Идентификатор);
			КонецЦикла;
		КонецЕсли;
		
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	ОбщегоНазначения.УдалитьДанныеИзБезопасногоХранилища(Источник.Ссылка);
	УстановитьПривилегированныйРежим(Ложь);
	
КонецПроцедуры

Процедура ПередУдалениемПланаОбмена(Источник, Отказ) Экспорт
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;

	Если ОбменДаннымиПовтИсп.ЭтоУзелОбменаДаннымиБСП(Источник.Ссылка)
		И НЕ Источник.ДополнительныеСвойства.Свойство("УдалениеНастройкиСинхронизации") Тогда
		
		Отказ = Истина;
				
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область МеханизмРегистрацииОбъектов

// Определяет список узлов получателей плана обмена ИмяПланаОбмена, для которых необходимо выполнить 
// регистрацию объекта Объект для последующей его выгрузки.
//
// Сначала, с помощью механизма выборочной регистрации объектов (ВРО) определяется,
// на каких планах обмена должен быть зарегистрирован объект к выгрузке.
// Затем, с помощью механизма регистрации объектов (ПРО, правила регистрации) определяется, 
// на каких узлах каждого плана обмена должен быть зарегистрирован объект.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого выполняется механизм регистрации.
//  Объект - Произвольный - изменяемые данные: объект, набор записей, константа или сведения об удалении объекта.
//  Отказ - Булево - признак возникновения ошибки во время регистрации объекта на узлах:
//    если во время регистрации объекта возникнут ошибки, то этот флаг будет установлен в значение Истина.
//  ДополнительныеПараметры - Структура - уточняющие сведения об изменяемых данных:
//    * ЭтоРегистр - Булево - значение Истина означает, что обрабатывается регистр.
//        Необязательный, значение по умолчанию Ложь.
//    * ЭтоУдалениеОбъекта - Булево - значение Истина означает, что обрабатывается удаление объекта.
//        Необязательный, значение по умолчанию Ложь.
//    * ЭтоКонстанта - Булево - значение Истина означает, что обрабатывается константа.
//        Необязательный, значение по умолчанию Ложь.
//    * РежимЗаписи - см. в синтакс-помощнике РежимЗаписиДокумента - режим записи документа (только для документов).
//        Необязательный, значение по умолчанию Неопределено.
//    * Замещение - Булево - режим записи регистра (только для регистров).
//        Необязательный, значение по умолчанию Неопределено.
//
Процедура ЗарегистрироватьИзменениеОбъекта(ИмяПланаОбмена, Объект, Отказ, ДополнительныеПараметры = Неопределено)
	
	// Проверка значения свойства ОбменДанными.Загрузка отсутствует по причине того, что в расположенным ниже коде,
	// реализована логика, регистрации изменений на узлах плана обмена, которая должна выполняться в том числе при
	// установке этого свойства равным Истина (на стороне кода, который выполняет попытку изменения/удаления данных).
	
	НеобязательныеПараметры = Новый Структура;
	НеобязательныеПараметры.Вставить("ЭтоРегистр", Ложь);
	НеобязательныеПараметры.Вставить("ЭтоУдалениеОбъекта", Ложь);
	НеобязательныеПараметры.Вставить("ЭтоКонстанта", Ложь);
	НеобязательныеПараметры.Вставить("РежимЗаписи", Неопределено);
	НеобязательныеПараметры.Вставить("Замещение", Неопределено);
	
	Если ДополнительныеПараметры <> Неопределено Тогда
		ЗаполнитьЗначенияСвойств(НеобязательныеПараметры, ДополнительныеПараметры);
	КонецЕсли;
	
	ЭтоРегистр = НеобязательныеПараметры.ЭтоРегистр;
	ЭтоУдалениеОбъекта = НеобязательныеПараметры.ЭтоУдалениеОбъекта;
	ЭтоКонстанта = НеобязательныеПараметры.ЭтоКонстанта;
	РежимЗаписи = НеобязательныеПараметры.РежимЗаписи;
	Замещение = НеобязательныеПараметры.Замещение;
	
	Попытка
		
		УстановитьПривилегированныйРежим(Истина);
		
		// Обновляем повторно используемые значения Механизма регистрации объектов.
		ОбменДаннымиСлужебный.ПроверитьКэшМеханизмаРегистрацииОбъектов();
		
		Если Объект.ДополнительныеСвойства.Свойство("РегистрироватьНаУзлахПлановОбменаПриОбновленииИБ") Тогда
			// Параметр РегистрироватьНаУзлахПлановОбменаПриОбновленииИБ указывает на то, что выполняется обновление данных ИБ.
			ОтключитьРегистрацию = Истина;
			Если Объект.ДополнительныеСвойства.РегистрироватьНаУзлахПлановОбменаПриОбновленииИБ = Неопределено Тогда
				// Принятие решения о необходимости регистрации данных для обмена выполняется автоматически,
				// по сопутствующей информации.
				Если Не (ЭтоРегистр Или ЭтоУдалениеОбъекта Или ЭтоКонстанта) И Объект.ЭтоНовый() Тогда
					// Новые ссылочные объекты должны всегда регистрироваться к обмену.
					ОтключитьРегистрацию = Ложь;
				ИначеЕсли ЗначениеЗаполнено(ПараметрыСеанса.ПараметрыОбработчикаОбновления) Тогда
					НазначениеПланаОбмена = ОбменДаннымиПовтИсп.НазначениеПланаОбмена(ИмяПланаОбмена);
					Если НазначениеПланаОбмена = "РИБСФильтром" Тогда
						// Регистрация может включаться только при использовании параллельного механизма обновления.
						// Если механизм используется, то регистрация определяется признаком выполнения обработчика в периферийном узле РИБ.
						ПараметрыОбработчикаОбновления = ПараметрыСеанса.ПараметрыОбработчикаОбновления;
						Если ПараметрыОбработчикаОбновления.РежимВыполненияОтложенныхОбработчиков = "Параллельно" Тогда
							ОтключитьРегистрацию = ПараметрыОбработчикаОбновления.ЗапускатьИВПодчиненномУзлеРИБСФильтрами;
						КонецЕсли;
					ИначеЕсли НазначениеПланаОбмена = "РИБ" Тогда
						ОтключитьРегистрацию = Не ПараметрыСеанса.ПараметрыОбработчикаОбновления.ЗапускатьТолькоВГлавномУзле;
					КонецЕсли;
				КонецЕсли;
			ИначеЕсли Объект.ДополнительныеСвойства.РегистрироватьНаУзлахПлановОбменаПриОбновленииИБ Тогда
				// Разработчик принял решение, что эти данные должны быть зарегистрированы для обмена.
				ОтключитьРегистрацию = Ложь;
			КонецЕсли;
			
			Если ОтключитьРегистрацию Тогда
				Возврат;
			КонецЕсли;
		ИначеЕсли Объект.ДополнительныеСвойства.Свойство("ОтключитьМеханизмРегистрацииОбъектов") Тогда
			// Регистрация объектов отключена принудительно.
			Возврат;
		КонецЕсли;
		
		ОбъектМетаданных = Объект.Метаданные();
		
		Если ОбщегоНазначения.РазделениеВключено() Тогда
			
			Если Не РазделенныйПланОбмена(ИмяПланаОбмена) Тогда
				ВызватьИсключение НСтр("ru = 'Регистрация изменений для неразделенных планов обмена не поддерживается.'");
			КонецЕсли;
			
			Если Не ОбменДаннымиПовтИсп.ПланОбменаИспользуетсяВМоделиСервиса(ИмяПланаОбмена) Тогда
				Возврат;
			КонецЕсли;
			
			Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
				МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
				ЭтоРазделенныеДанные = МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(
					ОбъектМетаданных.ПолноеИмя(), МодульРаботаВМоделиСервиса.РазделительОсновныхДанных());
			Иначе
				ЭтоРазделенныеДанные = Ложь;
			КонецЕсли;
			
			Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
				
				Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
					МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
					ЭтоСовместноРазделенныеДанные = МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(
						ОбъектМетаданных.ПолноеИмя(), МодульРаботаВМоделиСервиса.РазделительВспомогательныхДанных());
				Иначе
					ЭтоСовместноРазделенныеДанные = Ложь;
				КонецЕсли;
				
				Если Не ЭтоРазделенныеДанные И Не ЭтоСовместноРазделенныеДанные Тогда
					ВызватьИсключение НСтр("ru = 'Регистрация изменений неразделенных данных в разделенном режиме.'");
				КонецЕсли;
				
			Иначе
				
				Если ЭтоРазделенныеДанные Тогда
					ВызватьИсключение НСтр("ru = 'Регистрация изменений разделенных данных в неразделенном режиме.'");
				КонецЕсли;
					
				// Для неразделенных данных в неразделенном режиме выполняем регистрацию изменений данных
				// на всех узлах разделенных планов обмена.
				// Использование механизма правил регистрации в этом режиме не поддерживается.
				ЗарегистрироватьИзмененияНаВсехУзлахРазделенныхПлановОбмена(ИмяПланаОбмена, Объект);
				Возврат;
				
			КонецЕсли;
			
		КонецЕсли;
		
		// Определяем необходимость регистрации объекта на узле отправителе.
		Если Объект.ДополнительныеСвойства.Свойство("РегистрироватьОбъектНаУзлеОтправителе") Тогда
			Объект.ОбменДанными.Отправитель = Неопределено;
		КонецЕсли;
		
		Если Не ОбменДаннымиСлужебный.ОбменДаннымиВключен(ИмяПланаОбмена, Объект.ОбменДанными.Отправитель) Тогда
			Возврат;
		КонецЕсли;
		
		// При физическом удалении объекта ВРО не выполняем.
		ЗарегистрироватьОбъектКВыгрузке = ЭтоРегистр Или ЭтоУдалениеОбъекта Или ЭтоКонстанта;
		
		ОбъектМодифицирован = Объект.ДополнительныеСвойства.Свойство("ОтложеннаяЗапись")
			Или Объект.ДополнительныеСвойства.Свойство("ОтложенноеПроведение")
			Или ОбменДаннымиРегистрацияСервер.ОбъектМодифицированДляПланаОбмена(
				Объект, ОбъектМетаданных, ИмяПланаОбмена, РежимЗаписи, ЗарегистрироватьОбъектКВыгрузке);
		
		Если Не ОбъектМодифицирован Тогда
			
			Если ОбменДаннымиПовтИсп.АвтоРегистрацияРазрешена(ИмяПланаОбмена, ОбъектМетаданных.ПолноеИмя()) Тогда
				
				// Если объект не модифицирован и он регистрируется автоматически,
				// то удаляем все узлы по авторегистрации для текущего плана обмена.
				СократитьПолучателей(Объект, ВсеУзлыПланаОбмена(ИмяПланаОбмена));
				
			КонецЕсли;
			
			// Объект не модифицирован относительно текущего плана обмена
			// регистрацию на узлах этого плана обмена не выполняем.
			Возврат;
			
		КонецЕсли;
		
		Если Не ОбменДаннымиПовтИсп.АвтоРегистрацияРазрешена(ИмяПланаОбмена, ОбъектМетаданных.ПолноеИмя()) Тогда
			
			МассивУзловРезультат = Новый Массив;
			
			ДополнительныеПараметры = Новый Структура;
			ДополнительныеПараметры.Вставить("ОбъектМетаданных", ОбъектМетаданных);
			ДополнительныеПараметры.Вставить("ЭтоРегистр", ЭтоРегистр);
			ДополнительныеПараметры.Вставить("ЭтоУдалениеОбъекта", ЭтоУдалениеОбъекта);
			ДополнительныеПараметры.Вставить("Замещение", Замещение);
			ДополнительныеПараметры.Вставить("РежимЗаписи", РежимЗаписи);
			
			ПроверятьСсылку = ?(ЭтоРегистр ИЛИ ЭтоКонстанта, Ложь, Не Объект.ЭтоНовый() И Не ЭтоУдалениеОбъекта);
			ДополнительныеПараметры.Вставить("ПроверятьСсылку", ПроверятьСсылку);
			
			ВыполнитьПравилаРегистрацииОбъектовДляПланаОбмена(МассивУзловРезультат, Объект, ИмяПланаОбмена, ДополнительныеПараметры);
			
			Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
				МодульОбменДаннымиВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиВМоделиСервиса");
				МодульОбменДаннымиВМоделиСервиса.ПослеОпределенияПолучателей(Объект, МассивУзловРезультат, ИмяПланаОбмена);
			КонецЕсли;
			
			ИсключитьРегистрациюИзЗацикленныхУзлов(МассивУзловРезультат, Объект, ИмяПланаОбмена);
			
			ДополнитьПолучателей(Объект, МассивУзловРезультат);
			
		КонецЕсли;
				
	Исключение
		
		ШаблонТекста = НСтр("ru = 'Не удалось зарегистрировать изменения на узлах плана обмена %1 по причине: %2'", ОбщегоНазначения.КодОсновногоЯзыка());
		ПодробноеПредставление = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		
		ОписаниеОшибки = СтрШаблон(ШаблонТекста, ИмяПланаОбмена, ПодробноеПредставление);
		
		ЗаписьЖурналаРегистрации(ОбменДаннымиРегистрацияСервер.ИмяСобытияПравилаРегистрации(),
			УровеньЖурналаРегистрации.Ошибка, Метаданные.ПланыОбмена[ИмяПланаОбмена], , ОписаниеОшибки);
		
		ВызватьИсключение ОписаниеОшибки;
		
	КонецПопытки;
	
КонецПроцедуры

Процедура ЗарегистрироватьИзмененияНаВсехУзлахРазделенныхПлановОбмена(ИмяПланаОбмена, Объект)
	
	ШаблонТекста = "ПланОбмена.%1";
	ИмяПланаОбменаСтрокой = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонТекста, ИмяПланаОбмена);
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	ПланОбмена.Ссылка КАК Получатель
	|ИЗ
	|	&ИмяПланаОбмена КАК ПланОбмена
	|ГДЕ
	|	ПланОбмена.РегистрироватьИзменения
	|	И НЕ ПланОбмена.ЭтотУзел
	|	И НЕ ПланОбмена.ПометкаУдаления";

	Запрос = Новый Запрос;
	Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ИмяПланаОбмена", ИмяПланаОбменаСтрокой);
	Получатели = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Получатель");

	Для Каждого Получатель Из Получатели Цикл
		Объект.ОбменДанными.Получатели.Добавить(Получатель);
	КонецЦикла;
	
КонецПроцедуры

#КонецОбласти

#Область ПравилаРегистрацииОбъектов

// Процедура-обертка, выполняет код основной процедуры в режиме попытки
// (см. ВыполнитьПравилаРегистрацииОбъектовДляПланаОбменаПопыткаИсключение).
//
// Параметры:
//  МассивУзловРезультат - Массив - массив узлов получателей плана обмена ИмяПланаОбмена,
//   для которых необходимо выполнить регистрацию.
//  Объект - Произвольный - изменяемые данные: объект, набор записей, константа или сведения об удалении объекта.
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого выполняется механизм регистрации.
//  ДополнительныеПараметры - Структура - уточняющие сведения об изменяемых данных:
//    * ОбъектМетаданных - ОбъектМетаданных - объект метаданных, которому соответствуют изменяемые данные. Обязательный.
//    * ЭтоРегистр - Булево - значение Истина означает, что обрабатывается регистр.
//        Необязательный, значение по умолчанию Ложь.
//    * ЭтоУдалениеОбъекта - Булево - значение Истина означает, что обрабатывается удаление объекта.
//        Необязательный, значение по умолчанию Ложь.
//    * РежимЗаписи - см. в синтакс-помощнике РежимЗаписиДокумента - режим записи документа (только для документов).
//        Необязательный, значение по умолчанию Неопределено.
//    * Замещение - Булево - режим записи регистра (только для регистров).
//        Необязательный, значение по умолчанию Неопределено.
//    * ПроверятьСсылку - Булево - признак необходимости учитывать версию данных на момент до их изменения.
//        Необязательный, значение по умолчанию Ложь.
//    * Выгрузка - Булево - параметр определяет контекст выполнения правила регистрации.
//        Истина - правило регистрации выполняется в контексте выгрузки объекта.
//        Ложь - правило регистрации выполняется в контексте перед записью объекта.
//        Необязательный, значение по умолчанию Ложь.
//
Процедура ВыполнитьПравилаРегистрацииОбъектовДляПланаОбмена(МассивУзловРезультат, Объект, ИмяПланаОбмена, ДополнительныеПараметры)

	ОбъектМетаданных = ДополнительныеПараметры.ОбъектМетаданных;
	НеобязательныеПараметры = Новый Структура;
	НеобязательныеПараметры.Вставить("ЭтоРегистр", Ложь);
	НеобязательныеПараметры.Вставить("ЭтоУдалениеОбъекта", Ложь);
	НеобязательныеПараметры.Вставить("РежимЗаписи", Неопределено);
	НеобязательныеПараметры.Вставить("Замещение", Ложь);
	НеобязательныеПараметры.Вставить("ПроверятьСсылку", Ложь);
	НеобязательныеПараметры.Вставить("Выгрузка", Ложь);
	ЗаполнитьЗначенияСвойств(НеобязательныеПараметры, ДополнительныеПараметры);
	
	ДополнительныеПараметры = НеобязательныеПараметры;
	
	ДополнительныеПараметры.Вставить("ОбъектМетаданных", ОбъектМетаданных);
	
	Попытка
		ВыполнитьПравилаРегистрацииОбъектовДляПланаОбменаПопыткаИсключение(МассивУзловРезультат, Объект, ИмяПланаОбмена, ДополнительныеПараметры);
	Исключение
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка выполнения правил регистрации объектов для плана обмена %1.
			|Описание ошибки:
			|%2'"),
			ИмяПланаОбмена,
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
	КонецПопытки;
	
КонецПроцедуры

// Определяет список узлов получателей плана обмена ИмяПланаОбмена, для которых необходимо выполнить 
// регистрацию объекта Объект для последующей его выгрузки.
//
// Параметры:
//  МассивУзловРезультат - Массив - массив узлов получателей плана обмена ИмяПланаОбмена,
//   для которых необходимо выполнить регистрацию.
//  Объект - Произвольный - изменяемые данные: объект, набор записей, константа или сведения об удалении объекта.
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого выполняется механизм регистрации.
//  ДополнительныеПараметры - Структура - уточняющие сведения об изменяемых данных:
//    * ОбъектМетаданных - ОбъектМетаданных - объект метаданных, которому соответствуют изменяемые данные. Обязательный.
//    * ЭтоРегистр - Булево - значение Истина означает, что обрабатывается регистр. Обязательный.
//    * ЭтоУдалениеОбъекта - Булево - значение Истина означает, что обрабатывается удаление объекта. Обязательный.
//    * РежимЗаписи - см. в синтакс-помощнике РежимЗаписиДокумента - режим записи документа (только для документов).
//                    Обязательный.
//    * Замещение - Булево - режим записи регистра (только для регистров). Обязательный.
//    * ПроверятьСсылку - Булево - признак необходимости учитывать версию данных на момент до их изменения.
//                                 Обязательный.
//    * Выгрузка - Булево - параметр определяет контекст выполнения правила регистрации.
//        Истина - правило регистрации выполняется в контексте выгрузки объекта.
//        Ложь - правило регистрации выполняется в контексте перед записью объекта. Обязательный.
//
Процедура ВыполнитьПравилаРегистрацииОбъектовДляПланаОбменаПопыткаИсключение(МассивУзловРезультат, Объект, ИмяПланаОбмена, ДополнительныеПараметры)
	
	ОбъектМетаданных = ДополнительныеПараметры.ОбъектМетаданных;
	ЭтоРегистр = ДополнительныеПараметры.ЭтоРегистр;
	Замещение = ДополнительныеПараметры.Замещение;
	Выгрузка = ДополнительныеПараметры.Выгрузка;
	
	ПравилаРегистрацииОбъекта = Новый Массив;
	
	ИмяПрофиляБезопасности = ОбменДаннымиПовтИсп.ИмяПрофиляБезопасности(ИмяПланаОбмена);
	Если ИмяПрофиляБезопасности <> Неопределено Тогда
		УстановитьБезопасныйРежим(ИмяПрофиляБезопасности);
	КонецЕсли;
	
	Правила = ПравилаРегистрацииОбъекта(ИмяПланаОбмена, ОбъектМетаданных.ПолноеИмя());
	
	Для Каждого Правило Из Правила Цикл
		
		ПравилаРегистрацииОбъекта.Добавить(ПравилоРегистрацииСтруктурой(Правило, Правила.Колонки));
		
	КонецЦикла;
	
	Если ПравилаРегистрацииОбъекта.Количество() = 0 Тогда // Правила регистрации не заданы.
		
		// Если для объекта не созданы ПРО и отключена авторегистрация,
		// то регистрируем объект на всех узлах плана обмена кроме предопределенного.
		Получатели = ВсеУзлыПланаОбмена(ИмяПланаОбмена);
		
		ОбщегоНазначенияКлиентСервер.ДополнитьМассив(МассивУзловРезультат, Получатели, Истина);
		
	Иначе // Последовательно выполняем правила регистрации.
		
		Если ЭтоРегистр Тогда // для регистра
			
			Для Каждого ПРО Из ПравилаРегистрацииОбъекта Цикл
				
				// ОПРЕДЕЛЯЕМ ПОЛУЧАТЕЛЕЙ С РЕЖИМОМ ВЫГРУЗКИ "ПО УСЛОВИЮ"
				
				ОпределитьПолучателейПоУсловиюДляНабораЗаписей(МассивУзловРезультат, ПРО, Объект, ОбъектМетаданных, ИмяПланаОбмена, Замещение, Выгрузка);
				
				Если ЗначениеЗаполнено(ПРО.ИмяРеквизитаФлага) Тогда
					
					// ОПРЕДЕЛЯЕМ ПОЛУЧАТЕЛЕЙ С РЕЖИМОМ ВЫГРУЗКИ "ВСЕГДА"
					
					УстановитьПривилегированныйРежим(Истина);
					Получатели = УзлыДляРегистрацииПоУсловиюВыгружатьВсегда(ИмяПланаОбмена, ПРО.ИмяРеквизитаФлага);
					УстановитьПривилегированныйРежим(Ложь);
					
					ОбщегоНазначенияКлиентСервер.ДополнитьМассив(МассивУзловРезультат, Получатели, Истина);
					
					// ОПРЕДЕЛЯЕМ ПОЛУЧАТЕЛЕЙ С РЕЖИМОМ ВЫГРУЗКИ "ПРИ НЕОБХОДИМОСТИ"
					// для наборов записей выполнение регистрации "при необходимости" не имеет физического смысла.
					
				КонецЕсли;
				
			КонецЦикла;
			
		Иначе // для ссылочного типа
			
			Для Каждого ПРО Из ПравилаРегистрацииОбъекта Цикл
					
				// Если у объекта есть правило с обработчиком пакетной регистрации,
				// и это проверка регистрации перед выгрузкой, то пропускаем это правило,
				// т.к объект был проверен ранее пакетным обработчиком
				Если ПРО.ПакетноеВыполнениеОбработчиков 
					И Объект.ДополнительныеСвойства.Свойство("ПроверкаРегистрацииПередВыгрузкой")
					И НЕ Объект.ДополнительныеСвойства.Свойство("ИнтерактивноеДополнениеВыгрузки") Тогда
					Продолжить;
				КонецЕсли;
				
				// ОПРЕДЕЛЯЕМ ПОЛУЧАТЕЛЕЙ С РЕЖИМОМ ВЫГРУЗКИ "ПО УСЛОВИЮ"
				
				ОпределитьПолучателейПоУсловию(МассивУзловРезультат, ПРО, Объект, ИмяПланаОбмена, ДополнительныеПараметры);
				
				Если ЗначениеЗаполнено(ПРО.ИмяРеквизитаФлага) Тогда
					
					// ОПРЕДЕЛЯЕМ ПОЛУЧАТЕЛЕЙ С РЕЖИМОМ ВЫГРУЗКИ "ВСЕГДА"
					
					УстановитьПривилегированныйРежим(Истина);
					Получатели = УзлыДляРегистрацииПоУсловиюВыгружатьВсегда(ИмяПланаОбмена, ПРО.ИмяРеквизитаФлага);
					УстановитьПривилегированныйРежим(Ложь);
					
					ОбщегоНазначенияКлиентСервер.ДополнитьМассив(МассивУзловРезультат, Получатели, Истина);
					
					// ОПРЕДЕЛЯЕМ ПОЛУЧАТЕЛЕЙ С РЕЖИМОМ ВЫГРУЗКИ "ПРИ НЕОБХОДИМОСТИ"
					
					Если Не Объект.ЭтоНовый() Тогда
						
						УстановитьПривилегированныйРежим(Истина);
						Получатели = УзлыДляРегистрацииПоУсловиюВыгружатьПриНеобходимости(Объект.Ссылка, ИмяПланаОбмена, ПРО.ИмяРеквизитаФлага);
						УстановитьПривилегированныйРежим(Ложь);
						
						ОбщегоНазначенияКлиентСервер.ДополнитьМассив(МассивУзловРезультат, Получатели, Истина);
						
					КонецЕсли;
					
				КонецЕсли;
				
			КонецЦикла;
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Получает массив узлов плана обмена, для которых установлен признак "Выгружать всегда".
//
// Параметры:
//  ИмяПланаОбмена    - Строка - имя плана обмена, как объекта метаданных, по которому определяются узлы.
//  ИмяРеквизитаФлага - Строка - имя реквизита плана обмена, по которому устанавливается фильтр на выборку узлов.
//
// Возвращаемое значение:
//  Массив - массив узлов плана обмена, для которых установлен признак "Выгружать всегда".
//
Функция УзлыДляРегистрацииПоУсловиюВыгружатьВсегда(Знач ИмяПланаОбмена, Знач ИмяРеквизитаФлага)
	
	ШаблонТекста = "ПланОбмена.%1";
	ИмяПланаОбменаСтрокой = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонТекста, ИмяПланаОбмена);
	
	ШаблонТекстаПоле = "ШапкаПланаОбмена.%1";
	ИмяРеквизитаФлагаСтрокой = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонТекстаПоле, ИмяРеквизитаФлага);
	
	ТекстЗапроса = "ВЫБРАТЬ
	|	ШапкаПланаОбмена.Ссылка КАК Узел
	|ИЗ
	|	&ИмяПланаОбмена КАК ШапкаПланаОбмена
	|ГДЕ
	|	НЕ ШапкаПланаОбмена.ЭтотУзел
	|	И &ИмяРеквизитаФлага = ЗНАЧЕНИЕ(Перечисление.РежимыВыгрузкиОбъектовОбмена.ВыгружатьВсегда)
	|	И НЕ ШапкаПланаОбмена.ПометкаУдаления";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяПланаОбмена", ИмяПланаОбменаСтрокой);
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяРеквизитаФлага", ИмяРеквизитаФлагаСтрокой);
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	
	Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Узел");
КонецФункции

// Получает массив узлов плана обмена, для которых установлен признак "Выгружать при необходимости".
//
// Параметры:
//  Ссылка - ссылка на объект ИБ, для которого необходимо получить массив узлов, в которые объект ранее выгружался.
//  ИмяПланаОбмена    - Строка - имя плана обмена, как объекта метаданных, по которому определяются узлы.
//  ИмяРеквизитаФлага - Строка - имя реквизита плана обмена, по которому устанавливается фильтр на выборку узлов.
//
// Возвращаемое значение:
//  Массив - массив узлов плана обмена, для которых установлен признак "Выгружать при необходимости".
//
Функция УзлыДляРегистрацииПоУсловиюВыгружатьПриНеобходимости(Ссылка, Знач ИмяПланаОбмена, Знач ИмяРеквизитаФлага)
	
	МассивУзлов = Новый Массив;
	
	Если ОбменДаннымиСервер.ЭтоПланОбменаXDTO(ИмяПланаОбмена) Тогда
		МассивУзлов = ОбменДаннымиXDTOСервер.МассивУзловДляРегистрацииВыгружатьПриНеобходимости(
			Ссылка, ИмяПланаОбмена, ИмяРеквизитаФлага);
	Иначе
		
		ШаблонТекстаТаблица = "ПланОбмена.%1";
		ИмяПланаОбменаСтрокой = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонТекстаТаблица, ИмяПланаОбмена);
		
		ШаблонТекстаПоле = "ШапкаПланаОбмена.%1";
		ИмяРеквизитаФлагаСтрокой = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонТекстаПоле, ИмяРеквизитаФлага);
		
		ТекстЗапроса = "ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	ШапкаПланаОбмена.Ссылка КАК Узел
		|ИЗ
		|	&ИмяПланаОбмена КАК ШапкаПланаОбмена
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СоответствияОбъектовИнформационныхБаз КАК СоответствияОбъектовИнформационныхБаз
		|		ПО ШапкаПланаОбмена.Ссылка = СоответствияОбъектовИнформационныхБаз.УзелИнформационнойБазы
		|		И СоответствияОбъектовИнформационныхБаз.УникальныйИдентификаторИсточника = &Объект
		|ГДЕ
		|	НЕ ШапкаПланаОбмена.ЭтотУзел
		|	И &ИмяРеквизитаФлага = ЗНАЧЕНИЕ(Перечисление.РежимыВыгрузкиОбъектовОбмена.ВыгружатьПриНеобходимости)
		|	И НЕ ШапкаПланаОбмена.ПометкаУдаления
		|	И СоответствияОбъектовИнформационныхБаз.УникальныйИдентификаторИсточника = &Объект";
		
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяПланаОбмена", ИмяПланаОбменаСтрокой);
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяРеквизитаФлага", ИмяРеквизитаФлагаСтрокой);
		
		Запрос = Новый Запрос;
		Запрос.Текст = ТекстЗапроса;
		Запрос.УстановитьПараметр("Объект",   Ссылка);
		
		МассивУзлов = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Узел");
		
	КонецЕсли;
	
	Возврат МассивУзлов;
	
КонецФункции

Процедура ВыполнитьПравилоРегистрацииОбъектаДляНабораЗаписей(МассивУзловРезультат,
															ПРО,
															Объект,
															ОбъектМетаданных,
															ИмяПланаОбмена,
															Замещение,
															Выгрузка)
	
	// Определяем массив узлов-получателей по текущему набору записей.
	ОпределитьМассивПолучателейПоНаборуЗаписей(МассивУзловРезультат, Объект, ПРО, ОбъектМетаданных, ИмяПланаОбмена, Ложь, Выгрузка);
	
	Если Замещение И Не Выгрузка Тогда
		
		СтарыйНаборЗаписей = НаборЗаписей(Объект);
		
		// Определяем массив узлов-получателей по старому набору записей.
		ОпределитьМассивПолучателейПоНаборуЗаписей(МассивУзловРезультат, СтарыйНаборЗаписей, ПРО, ОбъектМетаданных, ИмяПланаОбмена, Истина, Ложь);
		
	КонецЕсли;
	
КонецПроцедуры

// Определяет список узлов получателей плана обмена ИмяПланаОбмена, для которых необходимо выполнить 
// регистрацию объекта Объект в соответствии с ПРО (универсальную часть) для последующей его выгрузки.
//
// Параметры:
//  МассивУзловРезультат - Массив - массив узлов получателей плана обмена ИмяПланаОбмена,
//   для которых необходимо выполнить регистрацию.
//  ПРО - СтрокаТаблицыЗначений - содержит сведения о правиле регистрации объектов, для которого выполняется процедура.
//  Объект - Произвольный - изменяемые данные: объект, набор записей, константа или сведения об удалении объекта.
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого выполняется механизм регистрации.
//  ДополнительныеПараметры - Структура - уточняющие сведения об изменяемых данных:
//    * ЭтоУдалениеОбъекта - Булево - значение Истина означает, что обрабатывается удаление объекта. Обязательный.
//    * РежимЗаписи - см. в синтакс-помощнике РежимЗаписиДокумента - режим записи документа (только для документов).
//                    Обязательный.
//    * ПроверятьСсылку - Булево - признак необходимости учитывать версию данных на момент до их изменения.
//                                 Обязательный.
//    * Выгрузка - Булево - параметр определяет контекст выполнения правила регистрации.
//        Истина - правило регистрации выполняется в контексте выгрузки объекта.
//        Ложь - правило регистрации выполняется в контексте перед записью объекта. Обязательный.
//
Процедура ВыполнитьПравилоРегистрацииОбъектаДляСсылочногоТипа(МассивУзловРезультат,
															ПРО,
															Объект,
															ИмяПланаОбмена,
															ДополнительныеПараметры)
	
	ЭтоУдалениеОбъекта = ДополнительныеПараметры.ЭтоУдалениеОбъекта;
	РежимЗаписи = ДополнительныеПараметры.РежимЗаписи;
	ПроверятьСсылку = ДополнительныеПараметры.ПроверятьСсылку;
	Выгрузка = ДополнительныеПараметры.Выгрузка;
	
	// ПРОБ - Правила регистрации по свойствам Объекта.
	// ПРОП - Правила регистрации по свойствам Плана обмена.
	// ПРО = ПРОБ <И> ПРОП
	
	ПолучитьЗначенияАлгоритмовКонстант(ПРО, ПРО.ОтборПоСвойствамОбъекта);
	
	// ПРОБ
	Если  Не ПРО.ПравилоПоСвойствамОбъектаПустое
		И Не ОбъектПрошелФильтрПравилРегистрацииПоСвойствам(ПРО, Объект, ПроверятьСсылку, РежимЗаписи) Тогда
		
		Возврат;
		
	КонецЕсли;
	
	// ПРОП
	// определяем узлы для регистрации объекта.
	ОпределитьМассивУзловДляОбъекта(МассивУзловРезультат, Объект, ИмяПланаОбмена, ПРО, ЭтоУдалениеОбъекта, ПроверятьСсылку, Выгрузка);
	
КонецПроцедуры

// Определяет список узлов получателей плана обмена ИмяПланаОбмена, для которых необходимо выполнить 
// регистрацию объекта Объект в соответствии с ПРО для последующей его выгрузки.
//
// Параметры:
//  МассивУзловРезультат - Массив - массив узлов получателей плана обмена ИмяПланаОбмена,
//   для которых необходимо выполнить регистрацию.
//  ПРО - СтрокаТаблицыЗначений - содержит сведения о правиле регистрации объектов, для которого выполняется процедура.
//  Объект - Произвольный - изменяемые данные: объект, набор записей, константа или сведения об удалении объекта.
//  ИмяПланаОбмена - Строка - имя плана обмена, для которого выполняется механизм регистрации.
//  ДополнительныеПараметры - Структура - уточняющие сведения об изменяемых данных:
//    * ОбъектМетаданных - ОбъектМетаданных - объект метаданных, которому соответствуют изменяемые данные. Обязательный.
//    * ЭтоУдалениеОбъекта - Булево - значение Истина означает, что обрабатывается удаление объекта. Обязательный.
//    * РежимЗаписи - см. в синтакс-помощнике РежимЗаписиДокумента - режим записи документа (только для документов).
//                    Обязательный.
//    * ПроверятьСсылку - Булево - признак необходимости учитывать версию данных на момент до их изменения.
//                                 Обязательный.
//    * Выгрузка - Булево - параметр определяет контекст выполнения правила регистрации.
//        Истина - правило регистрации выполняется в контексте выгрузки объекта.
//        Ложь - правило регистрации выполняется в контексте перед записью объекта. Обязательный.
//
Процедура ОпределитьПолучателейПоУсловию(МассивУзловРезультат, ПРО, Объект, ИмяПланаОбмена, ДополнительныеПараметры)
	
	ОбъектМетаданных = ДополнительныеПараметры.ОбъектМетаданных;
	Выгрузка = ДополнительныеПараметры.Выгрузка;
	
	// {Обработчик: Перед обработкой} Начало.
	Отказ = Ложь;
	
	ВыполнитьОбработчикПРОПередОбработкой(ПРО, Отказ, Объект, ОбъектМетаданных, Выгрузка);
	
	Если Отказ Тогда
		Возврат;
	КонецЕсли;
	// {Обработчик: Перед обработкой} Окончание.
	
	Получатели = Новый Массив;
	
	ВыполнитьПравилоРегистрацииОбъектаДляСсылочногоТипа(Получатели, ПРО, Объект, ИмяПланаОбмена, ДополнительныеПараметры);
	
	// {Обработчик: После обработки} Начало.
	Отказ = Ложь;
	
	ВыполнитьОбработчикПРОПослеОбработки(ПРО, Отказ, Объект, ОбъектМетаданных, Получатели, Выгрузка);
	
	Если Отказ Тогда
		Возврат;
	КонецЕсли;
	// {Обработчик: После обработки} Окончание.
	
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(МассивУзловРезультат, Получатели, Истина);
	
КонецПроцедуры

Процедура ОпределитьПолучателейПоУсловиюДляНабораЗаписей(МассивУзловРезультат,
														ПРО,
														Объект,
														ОбъектМетаданных,
														ИмяПланаОбмена,
														Замещение,
														Выгрузка)
	
	// {Обработчик: Перед обработкой} Начало.
	Отказ = Ложь;
	
	ВыполнитьОбработчикПРОПередОбработкой(ПРО, Отказ, Объект, ОбъектМетаданных, Выгрузка);
	
	Если Отказ Тогда
		Возврат;
	КонецЕсли;
	// {Обработчик: Перед обработкой} Окончание.
	
	Получатели = Новый Массив;
	
	ВыполнитьПравилоРегистрацииОбъектаДляНабораЗаписей(Получатели, ПРО, Объект, ОбъектМетаданных, ИмяПланаОбмена, Замещение, Выгрузка);
	
	// {Обработчик: После обработки} Начало.
	Отказ = Ложь;
	
	ВыполнитьОбработчикПРОПослеОбработки(ПРО, Отказ, Объект, ОбъектМетаданных, Получатели, Выгрузка);
	
	Если Отказ Тогда
		Возврат;
	КонецЕсли;
	// {Обработчик: После обработки} Окончание.
	
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(МассивУзловРезультат, Получатели, Истина);
	
КонецПроцедуры

Процедура ОпределитьМассивУзловДляОбъекта(МассивУзловРезультат,
										Источник,
										ИмяПланаОбмена,
										ПРО,
										ЭтоУдалениеОбъекта,
										ПроверятьСсылку,
										Выгрузка)
	
	// Получаем структуру значений свойств для объекта.
	ЗначенияСвойствОбъекта = ЗначенияСвойствДляОбъекта(Источник, ПРО);
	
	// Определяем массив узлов для регистрации объекта.
	МассивУзлов = ОпределитьМассивУзловПоЗначениямСвойств(ЗначенияСвойствОбъекта, ПРО, ИмяПланаОбмена, Источник, Выгрузка);
	
	// Добавляем узлы для регистрации.
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(МассивУзловРезультат, МассивУзлов, Истина);
	
	Если ПроверятьСсылку Тогда
		
		// Получаем структуру значений свойств для ссылки.
		УстановитьПривилегированныйРежим(Истина);
		ЗначенияСвойствСсылки = ЗначенияСвойствДляСсылки(Источник.Ссылка, ПРО.СвойстваОбъекта, ПРО.СвойстваОбъектаСтрокой, ПРО.ОбъектМетаданныхИмя);
		УстановитьПривилегированныйРежим(Ложь);
		
		// Определяем массив узлов для регистрации ссылки.
		МассивУзлов = ОпределитьМассивУзловПоЗначениямСвойствДополнительный(ЗначенияСвойствСсылки, ПРО, ИмяПланаОбмена, Источник);
		
		// Добавляем узлы для регистрации.
		ОбщегоНазначенияКлиентСервер.ДополнитьМассив(МассивУзловРезультат, МассивУзлов, Истина);
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ОпределитьМассивПолучателейПоНаборуЗаписей(МассивУзловРезультат,
													НаборЗаписей,
													ПРО,
													ОбъектМетаданных,
													ИмяПланаОбмена,
													ЭтоВерсияОбъектаДоИзменения,
													Выгрузка)
	
	// Получаем значение регистратора из отбора для набора записей.
	Регистратор = Неопределено;
	
	ЭлементОтбора = НаборЗаписей.Отбор.Найти("Регистратор");
	
	ЕстьРегистратор = ЭлементОтбора <> Неопределено;
	
	Если ЕстьРегистратор Тогда
		
		Регистратор = ЭлементОтбора.Значение;
		
	КонецЕсли;
	
	ПРО_СтрокиНабора = СкопироватьСтруктуру(ПРО);
	ПолучитьЗначенияАлгоритмовКонстант(ПРО_СтрокиНабора, ПРО_СтрокиНабора.ОтборПоСвойствамОбъекта);
	
	Для Каждого СтрокаНабора Из НаборЗаписей Цикл
		
		Если ЕстьРегистратор И СтрокаНабора["Регистратор"] = Неопределено Тогда
			
			Если Регистратор <> Неопределено Тогда
				
				СтрокаНабора["Регистратор"] = Регистратор;
				
			КонецЕсли;
			
		КонецЕсли;
		
		// ПРОБ
		Если Не ОбъектПрошелФильтрПравилРегистрацииПоСвойствам(ПРО_СтрокиНабора, СтрокаНабора, Ложь) Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		// ПРОП
		
		// Получаем структуру значений свойств для объекта.
		ЗначенияСвойствОбъекта = ЗначенияСвойствДляОбъекта(СтрокаНабора, ПРО_СтрокиНабора);
		
		Если ЭтоВерсияОбъектаДоИзменения Тогда
			
			// Определяем массив узлов для регистрации объекта.
			МассивУзлов = ОпределитьМассивУзловПоЗначениямСвойствДополнительный(ЗначенияСвойствОбъекта,
				ПРО_СтрокиНабора, ИмяПланаОбмена, СтрокаНабора, НаборЗаписей.ДополнительныеСвойства);
			
		Иначе
			
			// Определяем массив узлов для регистрации объекта.
			МассивУзлов = ОпределитьМассивУзловПоЗначениямСвойств(ЗначенияСвойствОбъекта, ПРО_СтрокиНабора,
				ИмяПланаОбмена, СтрокаНабора, Выгрузка, НаборЗаписей.ДополнительныеСвойства);
			
		КонецЕсли;
		
		// Добавляем узлы для регистрации.
		ОбщегоНазначенияКлиентСервер.ДополнитьМассив(МассивУзловРезультат, МассивУзлов, Истина);
		
	КонецЦикла;
	
КонецПроцедуры

// Возвращает структуру со значениями свойств объекта, полученных запросом из ИБ.
// Ключ структуры - имя свойства; Значение - значение свойства объекта.
//
// Параметры:
//  Ссылка - ссылка на объект ИБ, значения свойств которого требуется получить.
//
// Возвращаемое значение:
//  Структура - структура со значениями свойств объекта.
//
Функция ЗначенияСвойствДляСсылки(Ссылка, СвойстваОбъекта, Знач СвойстваОбъектаСтрокой, Знач ОбъектМетаданныхИмя)
	
	ЗначенияСвойств = СкопироватьСтруктуру(СвойстваОбъекта);
	
	Если ЗначенияСвойств.Количество() = 0 Тогда
		
		Возврат ЗначенияСвойств; // Возвращаем пустую структуру.
		
	КонецЕсли;
	
	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	&СвойстваОбъектаСтрокой
	|ИЗ
	|	&ОбъектМетаданныхИмя КАК Таблица
	|ГДЕ
	|	Таблица.Ссылка = &Ссылка";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&СвойстваОбъектаСтрокой", СвойстваОбъектаСтрокой);
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОбъектМетаданныхИмя",    ОбъектМетаданныхИмя);
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	Запрос.УстановитьПараметр("Ссылка", Ссылка);
	
	Попытка
		
		Выборка = Запрос.Выполнить().Выбрать();
		
	Исключение
		СтрокаСообщения = НСтр("ru = 'Ошибка при получении свойств ссылки. Ошибка выполнения запроса: [ОписаниеОшибки]'");
		СтрокаСообщения = СтрЗаменить(СтрокаСообщения, "[ОписаниеОшибки]", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение СтрокаСообщения;
	КонецПопытки;
	
	Если Выборка.Следующий() Тогда
		
		Для Каждого Элемент Из ЗначенияСвойств Цикл
			
			ЗначенияСвойств[Элемент.Ключ] = Выборка[Элемент.Ключ];
			
		КонецЦикла;
		
	КонецЕсли;
	
	Возврат ЗначенияСвойств;
КонецФункции

Функция ОпределитьМассивУзловПоЗначениямСвойств(ЗначенияСвойств, ПРО, Знач ИмяПланаОбмена, Объект, Знач Выгрузка, ДополнительныеСвойства = Неопределено)
	
	ИспользоватьКэш = Истина;
	ТекстЗапроса = ПРО.ТекстЗапроса;
	
	// {Обработчик: При обработке} Начало.
	Отказ = Ложь;
	
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("ТекстЗапроса", ТекстЗапроса);
	ДополнительныеПараметры.Вставить("ПараметрыЗапроса", ЗначенияСвойств);
	ДополнительныеПараметры.Вставить("ИспользоватьКэш", ИспользоватьКэш);
	ДополнительныеПараметры.Вставить("Выгрузка", Выгрузка);
	ДополнительныеПараметры.Вставить("ДополнительныеСвойства", ДополнительныеСвойства);
	
	ВыполнитьОбработчикПРОПриОбработке(Отказ, ПРО, Объект, ДополнительныеПараметры);
	
	ТекстЗапроса = ДополнительныеПараметры.ТекстЗапроса;
	ЗначенияСвойств = ДополнительныеПараметры.ПараметрыЗапроса;
	ИспользоватьКэш = ДополнительныеПараметры.ИспользоватьКэш;
	
	Если Отказ Тогда
		Возврат Новый Массив;
	КонецЕсли;
	// {Обработчик: При обработке} Окончание.
	
	Если ИспользоватьКэш Тогда
		
		Возврат ОбменДаннымиПовтИсп.МассивУзловПоЗначениямСвойств(ЗначенияСвойств, ТекстЗапроса, ИмяПланаОбмена, ПРО.ИмяРеквизитаФлага, Выгрузка);
		
	Иначе
		
		УстановитьПривилегированныйРежим(Истина);
		Возврат МассивУзловПоЗначениямСвойств(ЗначенияСвойств, ТекстЗапроса, ИмяПланаОбмена, ПРО.ИмяРеквизитаФлага, Выгрузка);
		
	КонецЕсли;
	
КонецФункции

Функция ОпределитьМассивУзловПоЗначениямСвойствДополнительный(ЗначенияСвойств, ПРО, Знач ИмяПланаОбмена, Объект, ДополнительныеСвойства = Неопределено)
	
	ИспользоватьКэш = Истина;
	ТекстЗапроса = ПРО.ТекстЗапроса;
	
	// {Обработчик: При обработке (дополнительный)} Начало.
	Отказ = Ложь;
	
	ВыполнитьОбработчикПРОПриОбработкеДополнительный(Отказ, ПРО, Объект, ТекстЗапроса, ЗначенияСвойств, ИспользоватьКэш, ДополнительныеСвойства);
	
	Если Отказ Тогда
		Возврат Новый Массив;
	КонецЕсли;
	// {Обработчик: При обработке (дополнительный)} Окончание.
	
	Если ИспользоватьКэш Тогда
		
		Возврат ОбменДаннымиПовтИсп.МассивУзловПоЗначениямСвойств(ЗначенияСвойств, ТекстЗапроса, ИмяПланаОбмена, ПРО.ИмяРеквизитаФлага);
		
	Иначе
		
		УстановитьПривилегированныйРежим(Истина);
		Возврат МассивУзловПоЗначениямСвойств(ЗначенияСвойств, ТекстЗапроса, ИмяПланаОбмена, ПРО.ИмяРеквизитаФлага);
		
	КонецЕсли;
	
КонецФункции

// Возвращает массив узлов плана обмена по заданным параметрам запроса и тексту запроса к таблице плана обмена.
//
//
Функция МассивУзловПоЗначениямСвойств(ЗначенияСвойств, Знач ТекстЗапроса, Знач ИмяПланаОбмена, Знач ИмяРеквизитаФлага, Знач Выгрузка = Ложь) Экспорт
	
	// Возвращаемое значение функции.
	МассивУзловРезультат = Новый Массив;
	
	// Для совместимости со старым параметром УсловиеОтбораПоРеквизитуФлагу
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "[УсловиеОтбораПоРеквизитуФлагу]", "И &УсловиеОтбораПоРеквизитуФлагу");
	
	// Подготавливаем запрос для получения узлов планов обмена.
	Запрос = Новый Запрос;
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "[ОбязательныеУсловия]",
				"И    ПланОбменаОсновнаяТаблица.Ссылка <> &" + ИмяПланаОбмена + "ЭтотУзел
				|И НЕ ПланОбменаОсновнаяТаблица.ПометкаУдаления
				|И &УсловиеОтбораПоРеквизитуФлагу
				|");
	//
	Если ПустаяСтрока(ИмяРеквизитаФлага) Тогда
		
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбораПоРеквизитуФлагу", "ИСТИНА");
		
	Иначе
		
		Если Выгрузка Тогда
			ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбораПоРеквизитуФлагу",
				"(ПланОбменаОсновнаяТаблица.[ИмяРеквизитаФлага] = ЗНАЧЕНИЕ(Перечисление.РежимыВыгрузкиОбъектовОбмена.ВыгружатьПоУсловию)
				|ИЛИ ПланОбменаОсновнаяТаблица.[ИмяРеквизитаФлага] = ЗНАЧЕНИЕ(Перечисление.РежимыВыгрузкиОбъектовОбмена.ВыгружатьВручную)
				|ИЛИ ПланОбменаОсновнаяТаблица.[ИмяРеквизитаФлага] = ЗНАЧЕНИЕ(Перечисление.РежимыВыгрузкиОбъектовОбмена.ПустаяСсылка))");
		Иначе
			ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбораПоРеквизитуФлагу",
				"(ПланОбменаОсновнаяТаблица.[ИмяРеквизитаФлага] = ЗНАЧЕНИЕ(Перечисление.РежимыВыгрузкиОбъектовОбмена.ВыгружатьПоУсловию)
				|ИЛИ ПланОбменаОсновнаяТаблица.[ИмяРеквизитаФлага] = ЗНАЧЕНИЕ(Перечисление.РежимыВыгрузкиОбъектовОбмена.ПустаяСсылка))");
		КонецЕсли;
		
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "[ИмяРеквизитаФлага]", ИмяРеквизитаФлага);
		
	КонецЕсли;
	
	// текст запроса
	Запрос.Текст = ТекстЗапроса;
	
	Запрос.УстановитьПараметр(ИмяПланаОбмена + "ЭтотУзел", ОбменДаннымиПовтИсп.ПолучитьЭтотУзелПланаОбмена(ИмяПланаОбмена));
	
	// Задаем значения параметров запроса из свойств объекта.
	Для Каждого Элемент Из ЗначенияСвойств Цикл
		
		Запрос.УстановитьПараметр("СвойствоОбъекта_" + Элемент.Ключ, Элемент.Значение);
		
	КонецЦикла;
	
	Попытка
		
		МассивУзловРезультат = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
		
	Исключение
		СтрокаСообщения = НСтр("ru = 'Ошибка при получении списка узлов получателей. Ошибка выполнения запроса: [ОписаниеОшибки]'");
		СтрокаСообщения = СтрЗаменить(СтрокаСообщения, "[ОписаниеОшибки]", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение СтрокаСообщения;
	КонецПопытки;
	
	Возврат МассивУзловРезультат;
КонецФункции

Функция ЗначенияСвойствДляОбъекта(Объект, ПРО)
	
	ЗначенияСвойств = Новый Структура;
	
	Для Каждого Элемент Из ПРО.СвойстваОбъекта Цикл
		
		ЗначенияСвойств.Вставить(Элемент.Ключ, ЗначениеСвойстваОбъекта(Объект, Элемент.Значение));
		
	КонецЦикла;
	
	Возврат ЗначенияСвойств;
	
КонецФункции

Функция ЗначениеСвойстваОбъекта(Объект, СтрокаСвойствОбъекта)
	
	Значение = Объект;
	
	МассивПодстрок = СтрРазделить(СтрокаСвойствОбъекта, ".");
	
	// Значение получаем с учетом возможного разыменования свойства.
	Для Каждого ИмяСвойства Из МассивПодстрок Цикл
		
		Значение = Значение[ИмяСвойства];
		
		Если Значение = Неопределено Тогда
			Возврат Неопределено;
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Значение;
	
КонецФункции

// Возвращаемое значение:
//   ТаблицаЗначений - таблица правил регистрации для текущего плана обмена.
//
Функция ПравилаРегистрацииОбъектовПланаОбмена(Знач ИмяПланаОбмена) Экспорт
	
	Возврат ОбменДаннымиПовтИсп.ПравилаРегистрацииОбъектовПланаОбмена(ИмяПланаОбмена);
	
КонецФункции

Функция ПравилаРегистрацииОбъекта(Знач ИмяПланаОбмена, Знач ПолноеИмяОбъекта) Экспорт
	
	Возврат ОбменДаннымиПовтИсп.ПравилаРегистрацииОбъекта(ИмяПланаОбмена, ПолноеИмяОбъекта);
	
КонецФункции

Функция ПравилоРегистрацииСтруктурой(Правило, Колонки)
	
	Результат = Новый Структура;
	
	Для Каждого Колонка Из Колонки Цикл
		
		Ключ = Колонка.Имя;
		Значение = Правило[Ключ];
		
		Если ТипЗнч(Значение) = Тип("ТаблицаЗначений") Тогда
			
			Результат.Вставить(Ключ, Значение.Скопировать());
			
		ИначеЕсли ТипЗнч(Значение) = Тип("ДеревоЗначений") Тогда
			
			Результат.Вставить(Ключ, Значение.Скопировать());
			
		ИначеЕсли ТипЗнч(Значение) = Тип("Структура") Тогда
			
			Результат.Вставить(Ключ, СкопироватьСтруктуру(Значение));
			
		Иначе
			
			Результат.Вставить(Ключ, Значение);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

Функция РазделенныйПланОбмена(Знач ИмяПланаОбмена)
	
	Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		ЭтоРазделенныеДанные = МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(
			"ПланОбмена." + ИмяПланаОбмена, МодульРаботаВМоделиСервиса.РазделительОсновныхДанных());
	Иначе
		ЭтоРазделенныеДанные = Ложь;
	КонецЕсли;
	
	Возврат ЭтоРазделенныеДанные;
	
КонецФункции

// Создает набор записей для регистра.
//
// Параметры:
//  ОбъектМетаданных регистра - для получения набора записей.
//
// Возвращаемое значение:
//  НаборЗаписей - в случае если для объекта метаданных не предусмотрено набора записей
//    вызывается исключение.
//
Функция НаборЗаписейПоТипу(ОбъектМетаданных)
	
	Если ОбщегоНазначения.ЭтоРегистрСведений(ОбъектМетаданных) Тогда
		
		Результат = РегистрыСведений[ОбъектМетаданных.Имя].СоздатьНаборЗаписей();
		
	ИначеЕсли ОбщегоНазначения.ЭтоРегистрНакопления(ОбъектМетаданных) Тогда
		
		Результат = РегистрыНакопления[ОбъектМетаданных.Имя].СоздатьНаборЗаписей();
		
	ИначеЕсли ОбщегоНазначения.ЭтоРегистрБухгалтерии(ОбъектМетаданных) Тогда
		
		Результат = РегистрыБухгалтерии[ОбъектМетаданных.Имя].СоздатьНаборЗаписей();
		
	ИначеЕсли ОбщегоНазначения.ЭтоРегистрРасчета(ОбъектМетаданных) Тогда
		
		Результат = РегистрыРасчета[ОбъектМетаданных.Имя].СоздатьНаборЗаписей();
		
	ИначеЕсли ОбщегоНазначения.ЭтоПоследовательность(ОбъектМетаданных) Тогда
		
		Результат = Последовательности[ОбъектМетаданных.Имя].СоздатьНаборЗаписей();
		
	ИначеЕсли ОбщегоНазначения.ЭтоРегистрРасчета(ОбъектМетаданных.Родитель())
		И Метаданные.РегистрыРасчета[ОбъектМетаданных.Родитель().Имя].Перерасчеты.Содержит(ОбъектМетаданных) Тогда
		
		Результат = РегистрыРасчета[ОбъектМетаданных.Родитель().Имя].Перерасчеты[ОбъектМетаданных.Имя].СоздатьНаборЗаписей();
		
	Иначе
		
		СтрокаСообщения = НСтр("ru = 'Для объекта метаданных %1 не предусмотрено набора записей.'");
		СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, ОбъектМетаданных.ПолноеИмя());
		ВызватьИсключение СтрокаСообщения;
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

#КонецОбласти

#Область ПравилаРегистрацииПоСвойствамОбъектов

Процедура ЗаполнитьЗначенияСвойствИзОбъекта(ДеревоЗначений, Объект)
	
	Для Каждого СтрокаДерева Из ДеревоЗначений.Строки Цикл
		
		Если СтрокаДерева.ЭтоГруппа Тогда
			
			ЗаполнитьЗначенияСвойствИзОбъекта(СтрокаДерева, Объект);
			
		Иначе
			
			СтрокаДерева.ЗначениеСвойства = ЗначениеСвойстваОбъекта(Объект, СтрокаДерева.СвойствоОбъекта);
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

// Параметры:
//   Объект - Произвольный
//   ДеревоЗначенийПриемник - ДеревоЗначений
//   ДеревоЗначенийИсточник - ДеревоЗначений
//
Процедура СоздатьДопустимыйОтборПоСвойствам(Объект, ДеревоЗначенийПриемник, ДеревоЗначенийИсточник)
	
	Для Каждого СтрокаДереваИсточника Из ДеревоЗначенийИсточник.Строки Цикл
		
		Если СтрокаДереваИсточника.ЭтоГруппа Тогда
			
			СтрокаДереваПриемника = ДеревоЗначенийПриемник.Строки.Добавить();
			
			ЗаполнитьЗначенияСвойств(СтрокаДереваПриемника, СтрокаДереваИсточника);
			
			СоздатьДопустимыйОтборПоСвойствам(Объект, СтрокаДереваПриемника, СтрокаДереваИсточника);
			
		Иначе
			
			Если ЦепочкаСвойствДействительна(Объект, СтрокаДереваИсточника.СвойствоОбъекта) Тогда
				
				СтрокаДереваПриемника = ДеревоЗначенийПриемник.Строки.Добавить();
				
				ЗаполнитьЗначенияСвойств(СтрокаДереваПриемника, СтрокаДереваИсточника);
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

// Предназначения для получения значений констант, которые вычисляются по произвольным выражениям.
// Значения вычисляются в привилегированном режиме.
//
Процедура ПолучитьЗначенияАлгоритмовКонстант(ПРО, ДеревоЗначений)
	
	Для Каждого СтрокаДерева Из ДеревоЗначений.Строки Цикл
		
		Если СтрокаДерева.ЭтоГруппа Тогда
			
			ПолучитьЗначенияАлгоритмовКонстант(ПРО, СтрокаДерева);
			
		Иначе
			
			Если СтрокаДерева.ВидЭлементаОтбора = ОбменДаннымиСервер.ЭлементОтбораСвойствоАлгоритмЗначения() Тогда
				
				Значение = Неопределено;
				
				Попытка
					
					#Если ВнешнееСоединение ИЛИ ТолстыйКлиентОбычноеПриложение Тогда
						
						ВыполнитьОбработчикВПривилегированномРежиме(Значение, СтрокаДерева.ЗначениеКонстанты);
						
					#Иначе
						
						УстановитьПривилегированныйРежим(Истина);
						Выполнить(СтрокаДерева.ЗначениеКонстанты);
						УстановитьПривилегированныйРежим(Ложь);
						
					#КонецЕсли
					
				Исключение
					
					СтрокаСообщения = НСтр("ru = 'Ошибка алгоритма вычисления значения константы:
												|План обмена: [ИмяПланаОбмена]
												|Объект метаданных: [ОбъектМетаданныхИмя]
												|Описание ошибки: [Описание]
												|Алгоритм:
												|// {Начало алгоритма}
												|[ЗначениеКонстанты]
												|// {Окончание алгоритма}'");
					СтрокаСообщения = СтрЗаменить(СтрокаСообщения, "[ИмяПланаОбмена]",      ПРО.ИмяПланаОбмена);
					СтрокаСообщения = СтрЗаменить(СтрокаСообщения, "[ОбъектМетаданныхИмя]", ПРО.ОбъектМетаданныхИмя);
					СтрокаСообщения = СтрЗаменить(СтрокаСообщения, "[Описание]",            ИнформацияОбОшибке().Описание);
					СтрокаСообщения = СтрЗаменить(СтрокаСообщения, "[ЗначениеКонстанты]",   Строка(СтрокаДерева.ЗначениеКонстанты));
					
					ВызватьИсключение СтрокаСообщения;
					
				КонецПопытки;
				
				СтрокаДерева.ЗначениеКонстанты = Значение;
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Функция ЦепочкаСвойствДействительна(Объект, Знач СтрокаСвойствОбъекта)
	
	Значение = Объект;
	
	МассивПодстрок = СтрРазделить(СтрокаСвойствОбъекта, ".");
	
	// Значение получаем с учетом возможного разыменования свойства.
	Для Каждого ИмяСвойства Из МассивПодстрок Цикл
		
		Попытка
			Значение = Значение[ИмяСвойства];
		Исключение
			Возврат Ложь;
		КонецПопытки;
		
	КонецЦикла;
	
	Возврат Истина;
КонецФункции

// Выполняем ПРОБ для ссылки и для объекта.
// Результат учитываем по условию "ИЛИ".
// Если объект прошел фильтр ПРОБ по значения из ссылки,
// то ПРОБ для значений объекта уже не выполняем.
//
Функция ОбъектПрошелФильтрПравилРегистрацииПоСвойствам(ПРО, Объект, ПроверятьСсылку, РежимЗаписи = Неопределено)
	
	НачальноеЗначениеСвойстваПроведен = Неопределено;
	
	Если РежимЗаписи <> Неопределено Тогда
		
		НачальноеЗначениеСвойстваПроведен = Объект.Проведен;
		
		Если РежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения Тогда
			
			Объект.Проведен = Ложь;
			
		ИначеЕсли РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
			
			Объект.Проведен = Истина;
			
		КонецЕсли;
		
	КонецЕсли;
	
	// ПРОБ по значению свойств Объекта.
	Если ОбъектПроходитФильтрПРОБ(ПРО, Объект) Тогда
		
		Если НачальноеЗначениеСвойстваПроведен <> Неопределено Тогда
			
			Объект.Проведен = НачальноеЗначениеСвойстваПроведен;
			
		КонецЕсли;
		
		Возврат Истина;
		
	КонецЕсли;
	
	Если НачальноеЗначениеСвойстваПроведен <> Неопределено Тогда
		
		Объект.Проведен = НачальноеЗначениеСвойстваПроведен;
		
	КонецЕсли;
	
	Если ПроверятьСсылку Тогда
		
		// ПРОБ по значению свойств Ссылки.
		Если ОбъектПроходитФильтрПРОБ(ПРО, Объект.Ссылка) Тогда
			
			Возврат Истина;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

Функция ОбъектПроходитФильтрПРОБ(ПРО, Объект)
	
	ПРО.ОтборПоСвойствам = Обработки.ЗагрузкаПравилРегистрацииОбъектов.ИнициализацияТаблицыОтборПоСвойствамОбъекта();
	
	СоздатьДопустимыйОтборПоСвойствам(Объект, ПРО.ОтборПоСвойствам, ПРО.ОтборПоСвойствамОбъекта);
	
	ЗаполнитьЗначенияСвойствИзОбъекта(ПРО.ОтборПоСвойствам, Объект);
	
	Возврат УсловиеИстинноДляВеткиДереваЗначений(ПРО.ОтборПоСвойствам);
	
КонецФункции

// По умолчанию считаем, что элементы отбора корневой группы сравниваются по условию "И".
// Поэтому параметр ЭтоОператорИ по умолчанию принимает значение Истина.
//
Функция УсловиеИстинноДляВеткиДереваЗначений(ДеревоЗначений, Знач ЭтоОператорИ = Истина)
	
	// инициализация
	Если ЭтоОператорИ Тогда // И
		Результат = Истина;
	Иначе // ИЛИ
		Результат = Ложь;
	КонецЕсли;
	
	Для Каждого СтрокаДерева Из ДеревоЗначений.Строки Цикл
		
		Если СтрокаДерева.ЭтоГруппа Тогда
			
			РезультатЭлемента = УсловиеИстинноДляВеткиДереваЗначений(СтрокаДерева, СтрокаДерева.ЭтоОператорИ);
		Иначе
			
			РезультатЭлемента = УсловиеИстинноДляЭлемента(СтрокаДерева, ЭтоОператорИ);
		КонецЕсли;
		
		Если ЭтоОператорИ Тогда // И
			
			Результат = Результат И РезультатЭлемента;
			
			Если Не Результат Тогда
				Возврат Ложь;
			КонецЕсли;
			
		Иначе // ИЛИ
			
			Результат = Результат ИЛИ РезультатЭлемента;
			
			Если Результат Тогда
				Возврат Истина;
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

Функция УсловиеИстинноДляЭлемента(СтрокаДерева, ЭтоОператорИ)
	
	ВидСравненияПравила = СтрокаДерева.ВидСравнения;
	
	Попытка
		
		Если      ВидСравненияПравила = "Равно"          Тогда Возврат СтрокаДерева.ЗначениеСвойства =  СтрокаДерева.ЗначениеКонстанты;
		ИначеЕсли ВидСравненияПравила = "НеРавно"        Тогда Возврат СтрокаДерева.ЗначениеСвойства <> СтрокаДерева.ЗначениеКонстанты;
		ИначеЕсли ВидСравненияПравила = "Больше"         Тогда Возврат СтрокаДерева.ЗначениеСвойства >  СтрокаДерева.ЗначениеКонстанты;
		ИначеЕсли ВидСравненияПравила = "БольшеИлиРавно" Тогда Возврат СтрокаДерева.ЗначениеСвойства >= СтрокаДерева.ЗначениеКонстанты;
		ИначеЕсли ВидСравненияПравила = "Меньше"         Тогда Возврат СтрокаДерева.ЗначениеСвойства <  СтрокаДерева.ЗначениеКонстанты;
		ИначеЕсли ВидСравненияПравила = "МеньшеИлиРавно" Тогда Возврат СтрокаДерева.ЗначениеСвойства <= СтрокаДерева.ЗначениеКонстанты;
		КонецЕсли;
		
	Исключение
		
		Возврат Ложь;
		
	КонецПопытки;
	
	Возврат Ложь;
	
КонецФункции

#КонецОбласти

#Область СобытияПравилРегистрацииОбъектов

Процедура ВыполнитьОбработчикПРОПередОбработкой(ПРО, Отказ, Объект, ОбъектМетаданных, Знач Выгрузка)
	
	Если ПРО.ЕстьОбработчикПередОбработкой Тогда
		
		Попытка
			Если ЗначениеЗаполнено(ПРО.ИмяМенеджераРегистрации) Тогда
			 	Менеджер = ОбщегоНазначения.ОбщийМодуль(ПРО.ИмяМенеджераРегистрации);
				Менеджер.ПередОбработкой(ПРО, Отказ, Объект, ОбъектМетаданных, Выгрузка);
			Иначе
				Выполнить(ПРО.ПередОбработкой);
			КонецЕсли;
		Исключение
			ВызватьИсключение ПодробноеПредставлениеОшибкиВыполненияОбработчика(
				"ПередОбработкой",
				ПРО.ИмяПланаОбмена,
				ПРО.ОбъектМетаданныхИмя,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьОбработчикПРОПриОбработке(Отказ, ПРО, Объект, ДополнительныеПараметры)
	
	ТекстЗапроса = ДополнительныеПараметры.ТекстЗапроса;
	ПараметрыЗапроса = ДополнительныеПараметры.ПараметрыЗапроса;
	ИспользоватьКэш = ДополнительныеПараметры.ИспользоватьКэш;
	Выгрузка = ДополнительныеПараметры.Выгрузка;
	ДополнительныеСвойства = ДополнительныеПараметры.ДополнительныеСвойства;
	
	Если ПРО.ЕстьОбработчикПриОбработке Тогда
		
		Попытка
			Если ЗначениеЗаполнено(ПРО.ИмяМенеджераРегистрации) Тогда
			 	Менеджер = ОбщегоНазначения.ОбщийМодуль(ПРО.ИмяМенеджераРегистрации);
				Менеджер.ПриОбработке(Отказ, ПРО, Объект, ТекстЗапроса, ПараметрыЗапроса, ИспользоватьКэш, Выгрузка, ДополнительныеСвойства);
			Иначе
				Выполнить(ПРО.ПриОбработке);
			КонецЕсли;
		Исключение
			ВызватьИсключение ПодробноеПредставлениеОшибкиВыполненияОбработчика(
				"ПриОбработке",
				ПРО.ИмяПланаОбмена,
				ПРО.ОбъектМетаданныхИмя,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;
		
	КонецЕсли;
	
	ДополнительныеПараметры.ТекстЗапроса = ТекстЗапроса;
	ДополнительныеПараметры.ПараметрыЗапроса = ПараметрыЗапроса;
	ДополнительныеПараметры.ИспользоватьКэш = ИспользоватьКэш;
	
КонецПроцедуры

Процедура ВыполнитьОбработчикПРОПриОбработкеДополнительный(Отказ, ПРО, Объект, ТекстЗапроса, ПараметрыЗапроса, ИспользоватьКэш, ДополнительныеСвойства = Неопределено)
	
	Если ПРО.ЕстьОбработчикПриОбработкеДополнительный Тогда
		
		Попытка
			Если ЗначениеЗаполнено(ПРО.ИмяМенеджераРегистрации) Тогда
				Менеджер = ОбщегоНазначения.ОбщийМодуль(ПРО.ИмяМенеджераРегистрации);
				Менеджер.ПриОбработкеДополнительный(Отказ, ПРО, Объект, ТекстЗапроса, ПараметрыЗапроса, ИспользоватьКэш, ДополнительныеСвойства);
			Иначе
				Выполнить(ПРО.ПриОбработкеДополнительный);
			КонецЕсли;
		Исключение
			ВызватьИсключение ПодробноеПредставлениеОшибкиВыполненияОбработчика(
				"ПриОбработкеДополнительный",
				ПРО.ИмяПланаОбмена,
				ПРО.ОбъектМетаданныхИмя,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыполнитьОбработчикПРОПослеОбработки(ПРО, Отказ, Объект, ОбъектМетаданных, Получатели, Знач Выгрузка)
	
	Если ПРО.ЕстьОбработчикПослеОбработки Тогда
		
		Попытка
			Если ЗначениеЗаполнено(ПРО.ИмяМенеджераРегистрации) Тогда
			 	Менеджер = ОбщегоНазначения.ОбщийМодуль(ПРО.ИмяМенеджераРегистрации);
				Менеджер.ПослеОбработки(ПРО, Отказ, Объект, ОбъектМетаданных, Получатели, Выгрузка);
			Иначе
				Выполнить(ПРО.ПослеОбработки);
			КонецЕсли;
		Исключение
			ВызватьИсключение ПодробноеПредставлениеОшибкиВыполненияОбработчика(
				"ПослеОбработки",
				ПРО.ИмяПланаОбмена,
				ПРО.ОбъектМетаданныхИмя,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;
		
	КонецЕсли;
	
КонецПроцедуры

Функция ПараметрыПакетнойРегистрации() Экспорт

	Параметры = Новый Структура;
	Параметры.Вставить("ЕстьПРО_СПакетнойРегистрацией", Ложь);
	Параметры.Вставить("ЕстьПРО_БезПакетнойРегистрации",Ложь);
	Параметры.Вставить("СсылкиПоФильтруПакетнойРегистрации", Новый Массив);
	Параметры.Вставить("СсылкиНеПоФильтруПакетнойРегистрации", Новый Массив);
	Параметры.Вставить("СозданиеНачальногоОбраза", Ложь);
	
	Возврат Параметры;
	
КонецФункции

Процедура ВыполнитьПакетнуюРегистрациюДляУзла(Узел, МассивСсылок, Параметры) Экспорт
	
	Если МассивСсылок.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
		
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(Узел);
	ПолноеИмяОбъекта = МассивСсылок[0].Метаданные().ПолноеИмя();
	
	РежимВыгрузкиОбъекта = ОбменДаннымиПовтИсп.РежимВыгрузкиОбъекта(ПолноеИмяОбъекта, Узел);
	
	Если РежимВыгрузкиОбъекта = Перечисления.РежимыВыгрузкиОбъектовОбмена.ВыгружатьВсегда Тогда
		
		Параметры.СсылкиПоФильтруПакетнойРегистрации = МассивСсылок;
		
	Иначе
	
		Правила = ПравилаРегистрацииОбъекта(ИмяПланаОбмена, ПолноеИмяОбъекта);
			
		Для Каждого ПРО Из Правила Цикл
			Если ПРО.ПакетноеВыполнениеОбработчиков Тогда
				
				МассивСсылокПРО = ОбщегоНазначения.СкопироватьРекурсивно(МассивСсылок, Ложь);
				ВыполнитьПакетнуюРегистрациюДляУзлаПопыткаИсключение(ПРО, МассивСсылокПРО, Узел);
				ОбщегоНазначенияКлиентСервер.ДополнитьМассив(Параметры.СсылкиПоФильтруПакетнойРегистрации, МассивСсылокПРО, Истина);
				
				Параметры.ЕстьПРО_СПакетнойРегистрацией = Истина;
				
			Иначе
				
				Параметры.ЕстьПРО_БезПакетнойРегистрации = Истина;
				
			КонецЕсли;
		КонецЦикла;
		
		Если Не Параметры.ЕстьПРО_СПакетнойРегистрацией Тогда
			
			Параметры.СсылкиНеПоФильтруПакетнойРегистрации = МассивСсылок;
			
		ИначеЕсли МассивСсылок.Количество() <> Параметры.СсылкиПоФильтруПакетнойРегистрации.Количество() Тогда
				
			Для Каждого Ссылка Из МассивСсылок Цикл
				Если Параметры.СсылкиПоФильтруПакетнойРегистрации.Найти(Ссылка) = Неопределено Тогда
					Параметры.СсылкиНеПоФильтруПакетнойРегистрации.Добавить(Ссылка);
				КонецЕсли;
			КонецЦикла;
		
		КонецЕсли;
		
	КонецЕсли;

	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЗащитаПерсональныхДанных") Тогда
		МодульЗащитаПерсональныхДанных = ОбщегоНазначения.ОбщийМодуль("ЗащитаПерсональныхДанных");
		
		Количество = Параметры.СсылкиПоФильтруПакетнойРегистрации.Количество();
		Для Сч = 1 По Количество Цикл
			
			Индекс = Количество - Сч;
			Ссылка = Параметры.СсылкиПоФильтруПакетнойРегистрации[Индекс];
			ОтправкаЭлемента = ОтправкаЭлементаДанных.Авто;
			МодульЗащитаПерсональныхДанных.ПриОтправкеДанных(Ссылка, ОтправкаЭлемента, Узел, Параметры.СозданиеНачальногоОбраза);
			
			Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда
				Параметры.СсылкиПоФильтруПакетнойРегистрации.Удалить(Индекс);
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЕсли;
		
КонецПроцедуры

Процедура ВыполнитьПакетнуюРегистрациюДляУзлаПопыткаИсключение(ПРО, МассивСсылок, Узел)
	
	РежимВыгрузки = Узел[ПРО.ИмяРеквизитаФлага];
	
	Если РежимВыгрузки <> Перечисления.РежимыВыгрузкиОбъектовОбмена.ВыгружатьПоУсловию
		И РежимВыгрузки <> Перечисления.РежимыВыгрузкиОбъектовОбмена.ВыгружатьВручную
		И РежимВыгрузки <> Перечисления.РежимыВыгрузкиОбъектовОбмена.ПустаяСсылка() Тогда
		
		МассивСсылок = Новый Массив;
		Возврат;
		
	КонецЕсли;
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(Узел);
	ИмяПрофиляБезопасности = ОбменДаннымиПовтИсп.ИмяПрофиляБезопасности(ИмяПланаОбмена);
	Если ИмяПрофиляБезопасности <> Неопределено Тогда
		УстановитьБезопасныйРежим(ИмяПрофиляБезопасности);
	КонецЕсли;
	
	Попытка
		Если ЗначениеЗаполнено(ПРО.ИмяМенеджераРегистрации) Тогда
			Менеджер = ОбщегоНазначения.ОбщийМодуль(ПРО.ИмяМенеджераРегистрации);
			Менеджер.ПакетнаяОбработка(ПРО, МассивСсылок, Узел);
		Иначе
			Выполнить(ПРО.ПакетнаяОбработка);
		КонецЕсли;
	Исключение
		МассивСсылок = Новый Массив;
		
		ВызватьИсключение ПодробноеПредставлениеОшибкиВыполненияОбработчика(
			"ПакетнаяОбработка",
			ПРО.ИмяПланаОбмена,
			ПРО.ОбъектМетаданныхИмя,
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
	КонецПопытки;
	
КонецПроцедуры

#КонецОбласти

#Область ВспомогательныеПроцедурыИФункции

Функция ПодробноеПредставлениеОшибкиВыполненияОбработчика(ИмяОбработчика, ИмяПланаОбмена, ИмяОбъектаМетаданных, ПредставлениеОшибки)
	
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Ошибка при выполнении обработчика: ""%1"";
		|План обмена: %2;
		|Объект метаданных: %3;
		|Описание ошибки: %4.'"),
		ИмяОбработчика,
		ИмяПланаОбмена,
		ИмяОбъектаМетаданных,
		ПредставлениеОшибки);
	
КонецФункции

Процедура ПриОтправкеДанных(ЭлементДанных, ОтправкаЭлемента, Знач Получатель, Знач СозданиеНачальногоОбраза, Знач Анализ)
	
	Если ТипЗнч(ЭлементДанных) = Тип("УдалениеОбъекта") Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЗащитаПерсональныхДанных") Тогда
		МодульЗащитаПерсональныхДанных = ОбщегоНазначения.ОбщийМодуль("ЗащитаПерсональныхДанных");
		МодульЗащитаПерсональныхДанных.ПриОтправкеДанных(ЭлементДанных, ОтправкаЭлемента, Получатель, СозданиеНачальногоОбраза);
	КонецЕсли;
	
	// Проверяем актуальность кэша механизма регистрации объектов.
	ОбменДаннымиСлужебный.ПроверитьКэшМеханизмаРегистрацииОбъектов();
	
	РежимВыгрузкиОбъекта = ОбменДаннымиПовтИсп.РежимВыгрузкиОбъекта(ЭлементДанных.Метаданные().ПолноеИмя(), Получатель);
	
	Если РежимВыгрузкиОбъекта = Перечисления.РежимыВыгрузкиОбъектовОбмена.ВыгружатьВсегда Тогда
		
		// Выгружаем элемент данных
		
	ИначеЕсли РежимВыгрузкиОбъекта = Перечисления.РежимыВыгрузкиОбъектовОбмена.ВыгружатьПоУсловию
		ИЛИ РежимВыгрузкиОбъекта = Перечисления.РежимыВыгрузкиОбъектовОбмена.ВыгружатьПриНеобходимости Тогда
		
		Если Не ДанныеСоответствуютФильтруПравилРегистрации(ЭлементДанных, Получатель) Тогда
			
			Если СозданиеНачальногоОбраза Тогда
				
				ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать;
				
			Иначе
				
				ОтправкаЭлемента = ОтправкаЭлементаДанных.Удалить;
				
			КонецЕсли;
			
		КонецЕсли;
		
	ИначеЕсли РежимВыгрузкиОбъекта = Перечисления.РежимыВыгрузкиОбъектовОбмена.ВыгружатьВручную Тогда
		
		Если ДанныеСоответствуютФильтруПравилРегистрации(ЭлементДанных, Получатель) Тогда
			
			Если Не Анализ Тогда
				
				// Удаляем регистрацию изменений данных, выгруженных вручную.
				ПланыОбмена.УдалитьРегистрациюИзменений(Получатель, ЭлементДанных);
				
			КонецЕсли;
			
		Иначе
			
			ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать;
			
		КонецЕсли;
			
	ИначеЕсли РежимВыгрузкиОбъекта = Перечисления.РежимыВыгрузкиОбъектовОбмена.НеВыгружать Тогда
		
		ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать;
		
	КонецЕсли;
	
	Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать
		И Не (ОбменДаннымиПовтИсп.ЭтоУзелРаспределеннойИнформационнойБазы(Получатель) И СозданиеНачальногоОбраза)
		И Не Анализ Тогда
		// При отказе в выгрузке объекта необходимо удалить регистрацию изменений.
		ПланыОбмена.УдалитьРегистрациюИзменений(Получатель, ЭлементДанных);
	КонецЕсли;
	
КонецПроцедуры

Функция ДанныеСоответствуютФильтруПравилРегистрации(ЭлементДанных, Знач Получатель)
	
	Результат = Истина;
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(Получатель);
	
	ОбъектМетаданных = ЭлементДанных.Метаданные();
	
	Если    ОбщегоНазначения.ЭтоСправочник(ОбъектМетаданных)
		ИЛИ ОбщегоНазначения.ЭтоДокумент(ОбъектМетаданных)
		ИЛИ ОбщегоНазначения.ЭтоПланВидовХарактеристик(ОбъектМетаданных)
		ИЛИ ОбщегоНазначения.ЭтоПланСчетов(ОбъектМетаданных)
		ИЛИ ОбщегоНазначения.ЭтоПланВидовРасчета(ОбъектМетаданных)
		ИЛИ ОбщегоНазначения.ЭтоБизнесПроцесс(ОбъектМетаданных)
		ИЛИ ОбщегоНазначения.ЭтоЗадача(ОбъектМетаданных) Тогда
		
		// Определяем массив узлов для регистрации объекта.
		МассивУзловДляРегистрацииОбъекта = Новый Массив;
		
		ДополнительныеПараметры = Новый Структура;
		ДополнительныеПараметры.Вставить("ОбъектМетаданных", ОбъектМетаданных);
		ДополнительныеПараметры.Вставить("Выгрузка", Истина);
		ВыполнитьПравилаРегистрацииОбъектовДляПланаОбмена(МассивУзловДляРегистрацииОбъекта,
														ЭлементДанных,
														ИмяПланаОбмена,
														ДополнительныеПараметры);
		//
		
		// Если в массиве нет текущего узла, то посылаем удаление объекта.
		Если МассивУзловДляРегистрацииОбъекта.Найти(Получатель) = Неопределено Тогда
			
			Результат = Ложь;
			
		КонецЕсли;
		
	ИначеЕсли ОбщегоНазначения.ЭтоРегистр(ОбъектМетаданных) Тогда
		
		ИсключаяСвойства = ?(ОбщегоНазначения.ЭтоРегистрНакопления(ОбъектМетаданных), "ВидДвижения", "");
		
		ДанныеДляПроверки = НаборЗаписейПоТипу(ОбъектМетаданных);
		
		Для Каждого ЭлементОтбораИсточник Из ЭлементДанных.Отбор Цикл
			
			ЭлементОтбораПриемник = ДанныеДляПроверки.Отбор.Найти(ЭлементОтбораИсточник.Имя);
			
			ЗаполнитьЗначенияСвойств(ЭлементОтбораПриемник, ЭлементОтбораИсточник);
			
		КонецЦикла;
		
		ДанныеДляПроверки.Добавить();
		
		ОбратныйИндекс = ЭлементДанных.Количество() - 1;
		
		Пока ОбратныйИндекс >= 0 Цикл
			
			ЗаполнитьЗначенияСвойств(ДанныеДляПроверки[0], ЭлементДанных[ОбратныйИндекс],, ИсключаяСвойства);
			
			// Определяем массив узлов для регистрации объекта.
			МассивУзловДляРегистрацииОбъекта = Новый Массив;
			
			ДополнительныеПараметры = Новый Структура;
			ДополнительныеПараметры.Вставить("ОбъектМетаданных", ОбъектМетаданных);
			ДополнительныеПараметры.Вставить("ЭтоРегистр", Истина);
			ДополнительныеПараметры.Вставить("Выгрузка", Истина);
			ВыполнитьПравилаРегистрацииОбъектовДляПланаОбмена(МассивУзловДляРегистрацииОбъекта,
															ДанныеДляПроверки,
															ИмяПланаОбмена,
															ДополнительныеПараметры);
			
			// Если в массиве нет текущего узла, то удаляем строку из набора.
			Если МассивУзловДляРегистрацииОбъекта.Найти(Получатель) = Неопределено Тогда
				
				ЭлементДанных.Удалить(ОбратныйИндекс);
				
			КонецЕсли;
			
			ОбратныйИндекс = ОбратныйИндекс - 1;
			
		КонецЦикла;
		
		Если ЭлементДанных.Количество() = 0 Тогда
			
			Результат = Ложь;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

// Заполняет значения реквизитов и табличных частей однотипных объектов информационной базы.
//
// Параметры:
//  Источник - объект информационной базы (СправочникОбъект, ДокументОбъект, ПланВидовХарактеристикОбъект и пр.)
//   который является источником данных для заполнения.
//
//  Приемник - объект информационной базы (СправочникОбъект, ДокументОбъект,
//  ПланВидовХарактеристикОбъект и пр.) который будет заполнен данными источника.
//
//  СписокСвойств - Строка - список свойств объекта и табличных частей, разделенных запятыми.
//                           Если параметр задан, то заполнение свойств объекта будет
//                           выполняться согласно заданным свойствам, при этом параметр.
//                           ИсключаяСвойства будет проигнорирован.
//
//  ИсключаяСвойства - Строка -  список свойств объекта и табличных частей, разделенных запятыми.
//                           Если параметр задан, то заполнение свойств объекта будет выполняться
//                           для всех свойств и табличных частей, исключая заданные свойства.
//
Процедура ЗаполнитьЗначенияСвойствОбъекта(Приемник, Источник, Знач СписокСвойств = Неопределено, Знач ИсключаяСвойства = Неопределено) Экспорт
	
	Если СписокСвойств <> Неопределено Тогда
		
		СписокСвойств = СтрЗаменить(СписокСвойств, " ", "");
		
		СписокСвойств = СтрРазделить(СписокСвойств, ",");
		
		ОбъектМетаданных = Приемник.Метаданные();
		
		ТабличныеЧасти = ТабличныеЧастиОбъекта(ОбъектМетаданных);
		
		СписокСвойствШапки = Новый Массив;
		ИспользуемыеТабличныеЧасти = Новый Массив;
		
		Для Каждого Свойство Из СписокСвойств Цикл
			
			Если ТабличныеЧасти.Найти(Свойство) <> Неопределено Тогда
				
				ИспользуемыеТабличныеЧасти.Добавить(Свойство);
				
			Иначе
				
				СписокСвойствШапки.Добавить(Свойство);
				
			КонецЕсли;
			
		КонецЦикла;
		
		СписокСвойствШапки = СтрСоединить(СписокСвойствШапки, ",");
		
		ЗаполнитьЗначенияСвойств(Приемник, Источник, СписокСвойствШапки);
		
		Для Каждого ТабличнаяЧасть Из ИспользуемыеТабличныеЧасти Цикл
			
			Приемник[ТабличнаяЧасть].Загрузить(Источник[ТабличнаяЧасть].Выгрузить());
			
		КонецЦикла;
		
	ИначеЕсли ИсключаяСвойства <> Неопределено Тогда
		
		ЗаполнитьЗначенияСвойств(Приемник, Источник,, ИсключаяСвойства);
		
		ОбъектМетаданных = Приемник.Метаданные();
		
		ТабличныеЧасти = ТабличныеЧастиОбъекта(ОбъектМетаданных);
		
		Для Каждого ТабличнаяЧасть Из ТабличныеЧасти Цикл
			
			Если СтрНайти(ИсключаяСвойства, ТабличнаяЧасть) <> 0 Тогда
				Продолжить;
			КонецЕсли;
			
			Приемник[ТабличнаяЧасть].Загрузить(Источник[ТабличнаяЧасть].Выгрузить());
			
		КонецЦикла;
		
	Иначе
		
		ЗаполнитьЗначенияСвойств(Приемник, Источник);
		
		ОбъектМетаданных = Приемник.Метаданные();
		
		ТабличныеЧасти = ТабличныеЧастиОбъекта(ОбъектМетаданных);
		
		Для Каждого ТабличнаяЧасть Из ТабличныеЧасти Цикл
			
			Приемник[ТабличнаяЧасть].Загрузить(Источник[ТабличнаяЧасть].Выгрузить());
			
		КонецЦикла;
		
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//   Объект - СправочникОбъект
//          - ДокументОбъект
//          - Произвольный - объект ссылочного типа.
//   ТаблицаРеквизитовСсылочногоТипа - ТаблицаЗначений
//
Процедура ВыполнитьРегистрациюОбъектовСсылочногоТипаПоСвойствамУзла(Объект, ТаблицаРеквизитовСсылочногоТипа)
	
	УзелИнформационнойБазы = Объект.Ссылка;
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелИнформационнойБазы);
	
	Для Каждого СтрокаТаблицы Из ТаблицаРеквизитовСсылочногоТипа Цикл
		
		Если ПустаяСтрока(СтрокаТаблицы.ИмяТабличнойЧасти) Тогда // реквизиты шапки
			
			Для Каждого Элемент Из СтрокаТаблицы.СтруктураРеквизитовРегистрации Цикл
				
				Ссылка = Объект[Элемент.Ключ];
				
				Если Не Ссылка.Пустая()
					И СоставПланаОбменаСодержитТип(ИмяПланаОбмена, ТипЗнч(Ссылка)) Тогда
					
					ПланыОбмена.ЗарегистрироватьИзменения(УзелИнформационнойБазы, Ссылка);
					
				КонецЕсли;
				
			КонецЦикла;
			
		Иначе // реквизиты табличной части
			
			ТабличнаяЧасть = Объект[СтрокаТаблицы.ИмяТабличнойЧасти];
			
			Для Каждого СтрокаТабличнойЧасти Из ТабличнаяЧасть Цикл
				
				Для Каждого Элемент Из СтрокаТаблицы.СтруктураРеквизитовРегистрации Цикл
					
					Ссылка = СтрокаТабличнойЧасти[Элемент.Ключ];
					
					Если Не Ссылка.Пустая()
						И СоставПланаОбменаСодержитТип(ИмяПланаОбмена, ТипЗнч(Ссылка)) Тогда
						
						ПланыОбмена.ЗарегистрироватьИзменения(УзелИнформационнойБазы, Ссылка);
						
					КонецЕсли;
					
				КонецЦикла;
				
			КонецЦикла;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Функция РеквизитыСсылочногоТипаУзлаПланаОбмена(УзелПланаОбменаОбъект)
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелПланаОбменаОбъект.Ссылка);
	
	// Выполняем инициализацию таблицы.
	Результат = ОбменДаннымиРегистрацияСервер.ИнициализацияТаблицыПравилВыборочнойРегистрацииОбъектов();
	
	ОбъектМетаданных = УзелПланаОбменаОбъект.Метаданные();
	ОбъектМетаданныхПолноеИмя = ОбъектМетаданных.ПолноеИмя();
	
	// Получаем реквизиты шапки
	Реквизиты = РеквизитыСсылочногоТипа(ОбъектМетаданных.Реквизиты, ИмяПланаОбмена);
	
	Если Реквизиты.Количество() > 0 Тогда
		
		СтрокаТаблицы = Результат.Добавить();
		СтрокаТаблицы.ИмяОбъекта                     = ОбъектМетаданныхПолноеИмя;
		СтрокаТаблицы.ИмяТабличнойЧасти              = "";
		СтрокаТаблицы.РеквизитыРегистрации           = КлючиСтруктурыВСтроку(Реквизиты);
		СтрокаТаблицы.СтруктураРеквизитовРегистрации = СкопироватьСтруктуру(Реквизиты);
		
	КонецЕсли;
	
	// Получаем реквизиты табличных частей.
	Для Каждого ТабличнаяЧасть Из ОбъектМетаданных.ТабличныеЧасти Цикл
		
		Реквизиты = РеквизитыСсылочногоТипа(ТабличнаяЧасть.Реквизиты, ИмяПланаОбмена);
		
		Если Реквизиты.Количество() > 0 Тогда
			
			СтрокаТаблицы = Результат.Добавить();
			СтрокаТаблицы.ИмяОбъекта                     = ОбъектМетаданныхПолноеИмя;
			СтрокаТаблицы.ИмяТабличнойЧасти              = ТабличнаяЧасть.Имя;
			СтрокаТаблицы.РеквизитыРегистрации           = КлючиСтруктурыВСтроку(Реквизиты);
			СтрокаТаблицы.СтруктураРеквизитовРегистрации = СкопироватьСтруктуру(Реквизиты);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

Функция РеквизитыСсылочногоТипа(Реквизиты, ИмяПланаОбмена)
	
	// Возвращаемое значение функции.
	Результат = Новый Структура;
	
	Для Каждого Реквизит Из Реквизиты Цикл
		
		МассивТипов = Реквизит.Тип.Типы();
		
		ЭтоСсылка = Ложь;
		
		Для Каждого Тип Из МассивТипов Цикл
			
			Если  ОбщегоНазначения.ЭтоСсылка(Тип)
				И СоставПланаОбменаСодержитТип(ИмяПланаОбмена, Тип) Тогда
				
				ЭтоСсылка = Истина;
				
				Прервать;
				
			КонецЕсли;
			
		КонецЦикла;
		
		Если ЭтоСсылка Тогда
			
			Результат.Вставить(Реквизит.Имя);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

Функция СоставПланаОбменаСодержитТип(ИмяПланаОбмена, Тип)
	
	Возврат Метаданные.ПланыОбмена[ИмяПланаОбмена].Состав.Содержит(Метаданные.НайтиПоТипу(Тип));
	
КонецФункции

// Создает новый экземпляр объекта Структура, заполняет объект данными указанной структуры.
//
// Параметры:
//  СтруктураИсточник - Структура - структура, копию которой необходимо получить.
//
// Возвращаемое значение:
//  Структура - копия переданной структуры.
//
Функция СкопироватьСтруктуру(СтруктураИсточник) Экспорт
	
	СтруктураРезультат = Новый Структура;
	
	Для Каждого Элемент Из СтруктураИсточник Цикл
		
		Если ТипЗнч(Элемент.Значение) = Тип("ТаблицаЗначений") Тогда
			
			СтруктураРезультат.Вставить(Элемент.Ключ, Элемент.Значение.Скопировать());
			
		ИначеЕсли ТипЗнч(Элемент.Значение) = Тип("ДеревоЗначений") Тогда
			
			СтруктураРезультат.Вставить(Элемент.Ключ, Элемент.Значение.Скопировать());
			
		ИначеЕсли ТипЗнч(Элемент.Значение) = Тип("Структура") Тогда
			
			СтруктураРезультат.Вставить(Элемент.Ключ, СкопироватьСтруктуру(Элемент.Значение));
			
		ИначеЕсли ТипЗнч(Элемент.Значение) = Тип("СписокЗначений") Тогда
			
			СтруктураРезультат.Вставить(Элемент.Ключ, Элемент.Значение.Скопировать());
			
		Иначе
			
			СтруктураРезультат.Вставить(Элемент.Ключ, Элемент.Значение);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат СтруктураРезультат;
КонецФункции

// Получает строку, содержащую ключи структуры, разделенные символом разделителя.
//
// Параметры:
//  Структура - Структура - структура, ключи которой преобразуются в строку.
//  Разделитель - Строка - разделитель, который вставляется в строку между ключами структуры.
//
// Возвращаемое значение:
//  Строка - строка, содержащая ключи структуры разделенные разделителем.
//
Функция КлючиСтруктурыВСтроку(Структура, Разделитель = ",") Экспорт
	
	Результат = "";
	
	Для Каждого Элемент Из Структура Цикл
		
		СимволРазделителя = ?(ПустаяСтрока(Результат), "", Разделитель);
		
		Результат = Результат + СимволРазделителя + Элемент.Ключ;
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

// Выполняет сравнение версий двух однотипных объектов.
//
// Параметры:
//  Данные1 - СправочникОбъект
//          - ДокументОбъект
//          - ПланВидовХарактеристикОбъект
//          - ПланВидовРасчетаОбъект
//          - ПланСчетовОбъект
//          - ПланОбменаОбъект
//          - БизнесПроцессОбъект
//          - ЗадачаОбъект - первая версия данных для сравнения.
//  Данные2 - СправочникОбъект
//          - ДокументОбъект
//          - ПланВидовХарактеристикОбъект
//          - ПланВидовРасчетаОбъект
//          - ПланСчетовОбъект
//          - ПланОбменаОбъект
//          - БизнесПроцессОбъект
//          - ЗадачаОбъект - вторая версия данных для сравнения.
//  СписокСвойств - Строка - список свойств объекта и табличных частей, разделенных запятыми.
//                           Если параметр задан, то заполнение свойств объекта будет
//                           выполняться согласно заданным свойствам, при этом параметр
//                           "ИсключаяСвойства" будет проигнорирован.
//  ИсключаяСвойства - Строка -  список свойств объекта и табличных частей, разделенных запятыми.
//                           Если параметр задан, то заполнение свойств объекта будет выполняться
//                           для всех свойств и табличных частей, исключая заданные свойства.
//
// Возвращаемое значение:
//   Булево - Истина - если версии данных различаются, иначе Ложь.
//
Функция ДанныеРазличаются(Данные1, Данные2, СписокСвойств = Неопределено, ИсключаяСвойства = Неопределено) Экспорт
	
	Если ТипЗнч(Данные1) <> ТипЗнч(Данные2) Тогда
		Возврат Истина;
	КонецЕсли;
	
	ОбъектМетаданных = Данные1.Метаданные(); // ОбъектМетаданных
	
	Если ОбщегоНазначения.ЭтоСправочник(ОбъектМетаданных) Тогда
		
		Если Данные1.ЭтоГруппа Тогда
			Объект1 = Справочники[ОбъектМетаданных.Имя].СоздатьГруппу();
		Иначе
			Объект1 = Справочники[ОбъектМетаданных.Имя].СоздатьЭлемент();
		КонецЕсли;
		
		Если Данные2.ЭтоГруппа Тогда
			Объект2 = Справочники[ОбъектМетаданных.Имя].СоздатьГруппу();
		Иначе
			Объект2 = Справочники[ОбъектМетаданных.Имя].СоздатьЭлемент();
		КонецЕсли;
		
	ИначеЕсли ОбщегоНазначения.ЭтоДокумент(ОбъектМетаданных) Тогда
		
		Объект1 = Документы[ОбъектМетаданных.Имя].СоздатьДокумент();
		Объект2 = Документы[ОбъектМетаданных.Имя].СоздатьДокумент();
		
	ИначеЕсли ОбщегоНазначения.ЭтоПланВидовХарактеристик(ОбъектМетаданных) Тогда
		
		Если Данные1.ЭтоГруппа Тогда
			Объект1 = ПланыВидовХарактеристик[ОбъектМетаданных.Имя].СоздатьГруппу();
		Иначе
			Объект1 = ПланыВидовХарактеристик[ОбъектМетаданных.Имя].СоздатьЭлемент();
		КонецЕсли;
		
		Если Данные2.ЭтоГруппа Тогда
			Объект2 = ПланыВидовХарактеристик[ОбъектМетаданных.Имя].СоздатьГруппу();
		Иначе
			Объект2 = ПланыВидовХарактеристик[ОбъектМетаданных.Имя].СоздатьЭлемент();
		КонецЕсли;
		
	ИначеЕсли ОбщегоНазначения.ЭтоПланВидовРасчета(ОбъектМетаданных) Тогда
		
		Объект1 = ПланыВидовРасчета[ОбъектМетаданных.Имя].СоздатьВидРасчета();
		Объект2 = ПланыВидовРасчета[ОбъектМетаданных.Имя].СоздатьВидРасчета();
		
	ИначеЕсли ОбщегоНазначения.ЭтоПланСчетов(ОбъектМетаданных) Тогда
		
		Объект1 = ПланыСчетов[ОбъектМетаданных.Имя].СоздатьСчет();
		Объект2 = ПланыСчетов[ОбъектМетаданных.Имя].СоздатьСчет();
		
	ИначеЕсли ОбщегоНазначения.ЭтоПланОбмена(ОбъектМетаданных) Тогда
		
		Объект1 = ПланыОбмена[ОбъектМетаданных.Имя].СоздатьУзел();
		Объект2 = ПланыОбмена[ОбъектМетаданных.Имя].СоздатьУзел();
		
	ИначеЕсли ОбщегоНазначения.ЭтоБизнесПроцесс(ОбъектМетаданных) Тогда
		
		Объект1 = БизнесПроцессы[ОбъектМетаданных.Имя].СоздатьБизнесПроцесс();
		Объект2 = БизнесПроцессы[ОбъектМетаданных.Имя].СоздатьБизнесПроцесс();
		
	ИначеЕсли ОбщегоНазначения.ЭтоЗадача(ОбъектМетаданных) Тогда
		
		Объект1 = Задачи[ОбъектМетаданных.Имя].СоздатьЗадачу();
		Объект2 = Задачи[ОбъектМетаданных.Имя].СоздатьЗадачу();
		
	Иначе
		
		ВызватьИсключение НСтр("ru = 'Задано недопустимое значение параметра [1] метода ОбщегоНазначения.ЗначенияСвойствИзменены.'");
		
	КонецЕсли;
	
	ЗаполнитьЗначенияСвойствОбъекта(Объект1, Данные1, СписокСвойств, ИсключаяСвойства);
	ЗаполнитьЗначенияСвойствОбъекта(Объект2, Данные2, СписокСвойств, ИсключаяСвойства);
	
	Возврат ДанныеИнформационнойБазыСтрокой(Объект1) <> ДанныеИнформационнойБазыСтрокой(Объект2);
	
КонецФункции

Функция ДанныеИнформационнойБазыСтрокой(Данные)
	
	ЗаписьXML = Новый ЗаписьXML;
	ЗаписьXML.УстановитьСтроку();
	
	ЗаписатьXML(ЗаписьXML, Данные, НазначениеТипаXML.Явное);
	
	Возврат ЗаписьXML.Закрыть();
	
КонецФункции

// Возвращает массив табличных частей объекта.
//
// Параметры:
//   ОбъектМетаданных - ОбъектМетаданных - ссылочный объект метаданных:
//     * ТабличныеЧасти - КоллекцияОбъектовМетаданных из ОбъектМетаданныхТабличнаяЧасть
//
// Возвращаемое значение:
//   Массив из Строка - коллекция табличных частей объекта.
//
Функция ТабличныеЧастиОбъекта(ОбъектМетаданных) Экспорт
	
	Результат = Новый Массив;
	
	Для Каждого ТабличнаяЧасть Из ОбъектМетаданных.ТабличныеЧасти Цикл
		
		Результат.Добавить(ТабличнаяЧасть.Имя);
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

// Параметры:
//   УзелПланаОбмена - ПланОбменаОбъект - узел плана обмена.
//   Настройки - Структура - структура со значениями настроек.
//
Процедура УстановитьЗначенияНаУзле(УзелПланаОбмена, Настройки)
	
	// УзелПланаОбмена - недоступный тип параметра для модулей с повторным использованием значений,
	// поэтому используется УзелПланаОбмена.Ссылка.
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелПланаОбмена.Ссылка);
	
	Для Каждого Элемент Из Настройки Цикл
		
		Ключ = Элемент.Ключ;
		Значение = Элемент.Значение;
		
		Если УзелПланаОбмена.Метаданные().Реквизиты.Найти(Ключ) = Неопределено
			И УзелПланаОбмена.Метаданные().ТабличныеЧасти.Найти(Ключ) = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Если ТипЗнч(Значение) = Тип("Массив") Тогда
			
			ДанныеРеквизита = СсылочныйТипИзПервогоРеквизитаТабличнойЧастиПланаОбмена(ИмяПланаОбмена, Ключ);
			
			Если ДанныеРеквизита = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			ТаблицаУзла = УзелПланаОбмена[Ключ];
			
			ТаблицаУзла.Очистить();
			
			Для Каждого СтрокаТаблицы Из Значение Цикл
				
				Если СтрокаТаблицы.Использовать Тогда
					
					МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоСсылке(ДанныеРеквизита.Тип.ПривестиЗначение());
					
					ЗначениеРеквизита = МенеджерОбъекта.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаТаблицы.УникальныйИдентификаторСсылки));
					
					ТаблицаУзла.Добавить()[ДанныеРеквизита.Имя] = ЗначениеРеквизита;
					
				КонецЕсли;
				
			КонецЦикла;
			
		ИначеЕсли ТипЗнч(Значение) = Тип("Структура") Тогда
			
			ЗаполнитьТаблицуУзлаПланаОбмена(УзелПланаОбмена, Значение, Ключ);
			
		Иначе // примитивные типы
			
			УзелПланаОбмена[Ключ] = Значение;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ЗаполнитьТаблицуУзлаПланаОбмена(Узел, СтруктураТабличнойЧасти, ИмяТаблицы)
	
	ТаблицаУзла = Узел[ИмяТаблицы];
	
	ТаблицаУзла.Очистить();
	
	Для Каждого Элемент Из СтруктураТабличнойЧасти Цикл
		
		Пока ТаблицаУзла.Количество() < Элемент.Значение.Количество() Цикл
			ТаблицаУзла.Добавить();
		КонецЦикла;
		
		ТаблицаУзла.ЗагрузитьКолонку(Элемент.Значение, Элемент.Ключ);
		
	КонецЦикла;
	
КонецПроцедуры

Функция СсылочныйТипИзПервогоРеквизитаТабличнойЧастиПланаОбмена(Знач ИмяПланаОбмена, Знач ИмяТабличнойЧасти)
	
	ТабличнаяЧасть = Метаданные.ПланыОбмена[ИмяПланаОбмена].ТабличныеЧасти[ИмяТабличнойЧасти];
	
	Для Каждого Реквизит Из ТабличнаяЧасть.Реквизиты Цикл
		
		Тип = Реквизит.Тип.Типы()[0];
		
		Если ОбщегоНазначения.ЭтоСсылка(Тип) Тогда
			
			Возврат Новый Структура("Имя, Тип", Реквизит.Имя, Реквизит.Тип);
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Неопределено;
КонецФункции

Процедура ПроверитьУстранениеПроблемыДокументаОбработкаПроведения(Источник, Отказ, РежимПроведения) Экспорт
	
	// Проверка значения свойства ОбменДанными.Загрузка отсутствует по причине того, что в расположенным ниже коде,
	// реализована логика, которая должна выполняться в том числе при установке этого свойства равным Истина
	// (на стороне кода, который выполняет попытку записи документа, а также при загрузке документа).
	
	РегистрыСведений.РезультатыОбменаДанными.ЗарегистрироватьУстранениеПроблемы(Источник, Перечисления.ТипыПроблемОбменаДанными.НепроведенныйДокумент);
	
КонецПроцедуры

Процедура ПроверитьУстранениеПроблемыОбъектаПриЗаписи(Источник, Отказ) Экспорт
	
	// Проверка значения свойства ОбменДанными.Загрузка отсутствует по причине того, что в расположенным ниже коде,
	// реализована логика, которая должна выполняться в том числе при установке этого свойства равным Истина
	// (на стороне кода, который выполняет попытку записи объекта, а также при загрузке объекта).
	
	РегистрыСведений.РезультатыОбменаДанными.ЗарегистрироватьУстранениеПроблемы(Источник, Перечисления.ТипыПроблемОбменаДанными.НезаполненныеРеквизиты);
	
КонецПроцедуры

// Получает текущее значение набора записей в информационной базе.
//
// Параметры:
//  Данные - набор записей регистров.
//
// Возвращаемое значение:
//  НаборЗаписей - содержащий текущее значение в информационной базе.
//
Функция НаборЗаписей(Знач Данные)
	
	ОбъектМетаданных = Данные.Метаданные();
	
	НаборЗаписей = НаборЗаписейПоТипу(ОбъектМетаданных);
	
	Для Каждого ЗначениеОтбора Из Данные.Отбор Цикл
		
		Если ЗначениеОтбора.Использование = Ложь Тогда
			Продолжить;
		КонецЕсли;
		
		СтрокаОтбора = НаборЗаписей.Отбор.Найти(ЗначениеОтбора.Имя);
		СтрокаОтбора.Значение = ЗначениеОтбора.Значение;
		СтрокаОтбора.Использование = Истина;
		
	КонецЦикла;
	
	НаборЗаписей.Прочитать();
	
	Возврат НаборЗаписей;
	
КонецФункции

// Проверяет режим запуска, устанавливает привилегированный режим и выполняет обработчик.
//
Процедура ВыполнитьОбработчикВПривилегированномРежиме(Значение, Знач СтрокаОбработчика)
	
	Если ТекущийРежимЗапуска() = РежимЗапускаКлиентскогоПриложения.УправляемоеПриложение Тогда
		ВызватьИсключение НСтр("ru = 'Метод не поддерживается в режиме управляемого приложения.'");
	КонецЕсли;
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		ВызватьИсключение НСтр("ru = 'Метод не поддерживается при работе в модели сервиса.'");
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	
	Выполнить(СтрокаОбработчика);
	
КонецПроцедуры

// Проверяем есть изменения ссылочных реквизитов узла плана обмена.
// Сведения будут использованы при наложении фильтров на уже зарегистрированные данные узла плана обмена.
// Необходимо понимать:
// - какие данные проходят через новые фильтры узла плана обмена.
//
Процедура УзелПланаОбменаМодифицированПоСсылочнымРеквизитам(УзелПланаОбменаОбъект, ПараметрыПроверкиУзла)
	
	Если УзелПланаОбменаОбъект = Неопределено Тогда
		
		Возврат;
		
	КонецЕсли;
	
	// Получаем реквизиты ссылочного типа, которые предположительно используются как значения фильтров правил регистрации
	// и проверяем их изменение в цикле
	ПараметрыПроверкиУзла.РеквизитыСсылочногоТипаУзлаПланаОбмена = РеквизитыСсылочногоТипаУзлаПланаОбмена(УзелПланаОбменаОбъект);
	
	Для Каждого СтрокаТаблицы Из ПараметрыПроверкиУзла.РеквизитыСсылочногоТипаУзлаПланаОбмена Цикл
		
		ЕстьИзмененияВерсийОбъектов = ОбменДаннымиРегистрацияСервер.ОпределитьИзмененияВерсийОбъекта(УзелПланаОбменаОбъект, СтрокаТаблицы);
		Если ЕстьИзмененияВерсийОбъектов Тогда
			
			ПараметрыПроверкиУзла.УзелМодифицирован = Истина;
			Прервать;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ИсключитьРегистрациюИзЗацикленныхУзлов(МассивУзловРезультат, Объект, ИмяПланаОбмена)
	
	ПланыОбменаБСП = ОбменДаннымиПовтИсп.ПланыОбменаБСП();
	Если ПланыОбменаБСП.Найти(ИмяПланаОбмена) = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ОбъектМетаданных = Объект.Метаданные();
	ЭтоОбъектСсылочногоТипа = ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(ОбъектМетаданных);
	
	Если ЭтоОбъектСсылочногоТипа
		И Объект.ОбменДанными.Загрузка Тогда
		
		Возврат;
		
	КонецЕсли;
	
	Если ОбменДаннымиПовтИсп.ЭтоПланОбменаXDTO(ИмяПланаОбмена) 
		И Объект.ОбменДанными.Отправитель <> Неопределено Тогда
		
		КоличествоУзлов = МассивУзловРезультат.Количество();
		Для Сч = 1 По КоличествоУзлов Цикл
			
			Индекс = КоличествоУзлов - Сч;
			Узел = МассивУзловРезультат.Получить(Индекс);
			
			Если Узел = Объект.ОбменДанными.Отправитель Тогда
				Продолжить;
			КонецЕсли;
			
			Если НЕ ОбменДаннымиПовтИсп.РегистрацияПриЗацикливании(Узел) Тогда
				
				Запись = РегистрыСведений.ОбъектыНезарегистрированныеПриЗацикливании.СоздатьМенеджерЗаписи();
				Запись.УзелИнформационнойБазы = Узел;
				
				Если ЭтоОбъектСсылочногоТипа Тогда
						
					Запись.Объект = Объект.Ссылка;
					Запись.ПредставлениеОбъекта = Объект.Ссылка;
						
				Иначе
					
					КлючРегистраСведений = Новый Структура();
					Для Каждого Измерение Из ОбъектМетаданных.Измерения Цикл
						КлючРегистраСведений.Вставить(Измерение.Имя, Объект.Отбор[Измерение.Имя].Значение);
					КонецЦикла; 
					
					Ключ = ОбъектМетаданных.Имя + ЗначениеВСтрокуВнутр(КлючРегистраСведений);
					Хеш = Новый ХешированиеДанных(ХешФункция.MD5);
					Хеш.Добавить(Ключ);	
					
					Запись.КлючРегистраСведений = СтрЗаменить(Строка(Хеш.ХешСумма), " ", "");
					Запись.ИмяРегистраСведений = ОбъектМетаданных.Имя;
					Запись.ИзмеренияРегистраСведений = Новый ХранилищеЗначения(КлючРегистраСведений);
					
					Шаблон = "%1: %2";
					Запись.ПредставлениеОбъекта = 
						СтроковыеФункции.ФорматированнаяСтрока(Шаблон, ОбъектМетаданных.Имя, Строка(Объект.Отбор)); 
					
				КонецЕсли;
				
				Запись.Записать(Истина);
					
				МассивУзловРезультат.Удалить(Индекс);
					
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЕсли;	
	
КонецПроцедуры

#КонецОбласти

#Область РаботаСКоллизиямиИзмененияДанныхПриОбмене

// Проверяет наличие коллизий при загрузке
// и выдает информацию есть ли коллизия при обмене.
// 
// Параметры:
//   ЭлементДанных - Произвольный - произвольные данные.
//   ПолучениеЭлемента - ПолучениеЭлементаДанных
//   Отправитель - ПланОбменаОбъект
//   ЭтоПолучениеОтГлавного - Булево
//
Процедура ПроверитьКоллизиюИзмененийДанных(ЭлементДанных, ПолучениеЭлемента, Знач Отправитель, Знач ЭтоПолучениеОтГлавного)
	
	Если ТипЗнч(ЭлементДанных) = Тип("УдалениеОбъекта") Тогда
		
		Возврат;
		
	ИначеЕсли ЭлементДанных.ДополнительныеСвойства.Свойство("ОбменДанными") И ЭлементДанных.ДополнительныеСвойства.ОбменДанными.АнализДанных Тогда
		
		Возврат;
		
	КонецЕсли;
	
	Отправитель = Отправитель.Ссылка;
	МетаданныеОбъекта = ЭлементДанных.Метаданные();
	ЭтоСсылочныйТип = ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(МетаданныеОбъекта);
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(Отправитель);
	Если Не ОбменДаннымиПовтИсп.ЭтоПланОбменаРаспределеннойИнформационнойБазы(ИмяПланаОбмена)
		И Не ОбменДаннымиПовтИсп.ПланОбменаСодержитОбъект(ИмяПланаОбмена, МетаданныеОбъекта.ПолноеИмя()) Тогда
		Возврат;
	КонецЕсли;
	
	ЕстьКоллизия = ПланыОбмена.ИзменениеЗарегистрировано(Отправитель, ЭлементДанных);
	
	// Выполняем дополнительную проверку на изменение объекта
	// если объект до коллизии и после коллизии не изменен,
	// то считаем, что коллизии нет.
	Если ЕстьКоллизия Тогда
		
		Если ЭтоСсылочныйТип И Не ЭлементДанных.Ссылка.Пустая() Тогда
			
			ОбъектВБазе = ЭлементДанных.Ссылка.ПолучитьОбъект();
			СсылкаСуществует = (ОбъектВБазе <> Неопределено);
			
		Иначе
			СсылкаСуществует = Ложь;
			ОбъектВБазе = Неопределено;
		КонецЕсли;
		
		СтрокаОбъектаДоИзменения    = ДанныеОбъектаСтрокойДоИзменения(ЭлементДанных, МетаданныеОбъекта, ЭтоСсылочныйТип, СсылкаСуществует, ОбъектВБазе);
		СтрокаОбъектаПослеИзменения = ДанныеОбъектаСтрокойПослеИзменения(ЭлементДанных, МетаданныеОбъекта);
		
		// Если значения совпадают, то коллизии нет.
		Если СтрокаОбъектаДоИзменения = СтрокаОбъектаПослеИзменения Тогда
			
			ЕстьКоллизия = Ложь;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Если ЕстьКоллизия Тогда
		
		ОбменДаннымиПереопределяемый.ПриКоллизииИзмененийДанных(ЭлементДанных, ПолучениеЭлемента, Отправитель, ЭтоПолучениеОтГлавного);
		
		Если ПолучениеЭлемента = ПолучениеЭлементаДанных.Авто Тогда
			ПолучениеЭлемента = ?(ЭтоПолучениеОтГлавного, ПолучениеЭлементаДанных.Принять, ПолучениеЭлементаДанных.Игнорировать);
		КонецЕсли;
		
		ЗаписатьОбъект = (ПолучениеЭлемента = ПолучениеЭлементаДанных.Принять);
		
		ЗарегистрироватьПредупреждениеОКоллизииВЖурналеРегистрации(ЭлементДанных, МетаданныеОбъекта, ЗаписатьОбъект, ЭтоСсылочныйТип);
		
		Если Не ЭтоСсылочныйТип Тогда
			Возврат;
		КонецЕсли;
			
		Если ОбменДаннымиПовтИсп.ИспользуетсяВерсионирование(Отправитель) Тогда
			Если СсылкаСуществует Тогда
				
				Если ЗаписатьОбъект Тогда
					ПредупреждениеСинхронизации = НСтр("ru = 'Предыдущая версия (автоматическое разрешение конфликта).'");
				Иначе
					ПредупреждениеСинхронизации = НСтр("ru = 'Текущая версия (автоматическое разрешение конфликта).'");
				КонецЕсли;
				
				СведенияОВерсииОбъекта = Новый Структура("ПредупреждениеСинхронизации, ТипВерсииОбъекта", ПредупреждениеСинхронизации, "НепринятыеДанныеПоКоллизии");
				ПриСозданииВерсииОбъекта(ОбъектВБазе, СведенияОВерсииОбъекта, СсылкаСуществует, Отправитель);
				
			КонецЕсли;
			
			СведенияОВерсииОбъекта = Новый Структура;
			Если ЗаписатьОбъект Тогда
				СведенияОВерсииОбъекта.Вставить("АвторВерсии", Отправитель);
				СведенияОВерсииОбъекта.Вставить("ТипВерсииОбъекта", "ПринятыеДанныеПоКоллизии");
				СведенияОВерсииОбъекта.Вставить("ПредупреждениеСинхронизации", НСтр("ru = 'Текущая версия (автоматическое разрешение конфликта).'"));
			Иначе
				СведенияОВерсииОбъекта.Вставить("АвторВерсии", Отправитель);
				СведенияОВерсииОбъекта.Вставить("ТипВерсииОбъекта", "НепринятыеДанныеПоКоллизии");
				СведенияОВерсииОбъекта.Вставить("ПредупреждениеСинхронизации", НСтр("ru = 'Отклоненная версия (автоматическое разрешение конфликта).'"));
			КонецЕсли;
			Если ОбменДаннымиПовтИсп.ЭтоУзелРаспределеннойИнформационнойБазы(Отправитель) Тогда
				ПриСозданииВерсииОбъекта(ЭлементДанных, СведенияОВерсииОбъекта, СсылкаСуществует, Отправитель);
			Иначе
				ЭлементДанных.ДополнительныеСвойства.Вставить("СведенияОВерсииОбъекта", СведенияОВерсииОбъекта);
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Выполняет проверку на наличие запрета загрузки по дате.
//
// Параметры:
//   ЭлементДанных - СправочникОбъект
//                 - ДокументОбъект
//                 - РегистрСведенийНаборЗаписей -
//                   Данные, которые были зачитаны из сообщения обмена, но еще не были записаны в ИБ.
//   ПолучениеЭлемента - ПолучениеЭлементаДанных
//   Отправитель   - ПланОбменаОбъект
//
Процедура ПроверитьНаличиеЗапретаЗагрузкиПоДате(ЭлементДанных, ПолучениеЭлемента, Знач Отправитель)
	
	Если ОбменДаннымиПовтИсп.ЭтоУзелРаспределеннойИнформационнойБазы(Отправитель.Ссылка) Тогда
		Возврат;
	КонецЕсли;
	
	ЭтоУдалениеОбъекта = (ТипЗнч(ЭлементДанных) = Тип("УдалениеОбъекта"));
	
	Если Не ЭтоУдалениеОбъекта
		И ОбщегоНазначения.ЭтоКонстанта(ЭлементДанных.Метаданные()) Тогда
		Возврат;
	КонецЕсли;
	
	Если Не ЭтоУдалениеОбъекта 
		И ЭлементДанных.ДополнительныеСвойства.Свойство("УдалятьСозданныеПоКлючевымСвойствам") Тогда
			Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ДатыЗапретаИзменения") Тогда
		МодульДатыЗапретаИзменения = ОбщегоНазначения.ОбщийМодуль("ДатыЗапретаИзменения");
		
		Отказ = Ложь;
		ОписаниеОшибки = "";
		
		МодульДатыЗапретаИзменения.ПроверитьДатыЗапретаЗагрузкиДанных(ЭлементДанных,
			Отправитель.Ссылка, Отказ, ОписаниеОшибки);
		
		Если Отказ Тогда
			ЗарегистрироватьЗапретЗагрузкиДанныхПоДате(
				?(ЭтоУдалениеОбъекта, ЭлементДанных.Ссылка.ПолучитьОбъект(), ЭлементДанных), Отправитель, ОписаниеОшибки);
			ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать;
		КонецЕсли;
		
	КонецЕсли;
	
	Если Не ЭтоУдалениеОбъекта Тогда
		ЭлементДанных.ДополнительныеСвойства.Вставить("ПропуститьПроверкуЗапретаИзменения");
	КонецЕсли;
	
КонецПроцедуры

// Регистрирует запрет на загрузку данных по причине установленной даты запрета загрузки данных
// в журнале регистрации. Для ссылочных типов при наличии подсистемы ВерсионированиеОбъектов
// регистрирует его так же в мониторе проблем обмена.
// Для проверки наличия запрета загрузки по дате см. процедуру
// общего модуля ДатыЗапретаИзменения.ПроверитьДатыЗапретаЗагрузкиДанных.
//
// Параметры:
//  Объект - объект ссылочного типа для которого выполняется регистрация запрета.
//  УзелОбмена - ПланОбменаСсылка - узел информационной базы из которой получен объект.
//  СообщениеОбОшибке - Строка - подробное описание причины отказа от загрузки.
//
Процедура ЗарегистрироватьЗапретЗагрузкиДанныхПоДате(ЭлементДанных, Отправитель, СообщениеОбОшибке)
	
	ЗаписьЖурналаРегистрации(ОбменДаннымиСервер.СобытиеЖурналаРегистрацииОбменДанными(),
		УровеньЖурналаРегистрации.Предупреждение, , ЭлементДанных, СообщениеОбОшибке);
	
	Если ОбменДаннымиПовтИсп.ИспользуетсяВерсионирование(Отправитель.Ссылка) И ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(ЭлементДанных.Метаданные()) Тогда
		
		СсылкаНаОбъект = ЭлементДанных.Ссылка;
		СсылкаСуществует = ОбщегоНазначения.СсылкаСуществует(СсылкаНаОбъект);
		
		ТипВерсииОбъекта = "";
		Если СсылкаСуществует Тогда
			
			ОбъектВБазе = СсылкаНаОбъект.ПолучитьОбъект();
			
			ПредупреждениеСинхронизации = НСтр("ru = 'Версия создана при синхронизации данных.'");
			СведенияОВерсииОбъекта = Новый Структура("ПредупреждениеСинхронизации", ПредупреждениеСинхронизации);
			
			ПриСозданииВерсииОбъекта(ОбъектВБазе, СведенияОВерсииОбъекта, СсылкаСуществует, Отправитель);
			
			СтрокаСообщенияОбОшибке = СообщениеОбОшибке;
			ТипВерсииОбъекта = "НепринятыйПоДатеЗапретаОбъектСуществуетВБазе";
			
		Иначе
			
			СтрокаСообщенияОбОшибке = НСтр("ru = '%1 запрещено загружать в запрещенный период.%2%2%3'");
			СтрокаСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщенияОбОшибке, Строка(ЭлементДанных), Символы.ПС, СообщениеОбОшибке);
			ТипВерсииОбъекта = "НепринятыйПоДатеЗапретаОбъектНеСуществуетВБазе";
			
		КонецЕсли;
		
		НепринятыеПоДатеЗапрета = Новый Соответствие;
		Если Не Отправитель.ДополнительныеСвойства.Свойство("НепринятыеПоДатеЗапрета") Тогда
			Отправитель.ДополнительныеСвойства.Вставить("НепринятыеПоДатеЗапрета", НепринятыеПоДатеЗапрета);
		Иначе
			НепринятыеПоДатеЗапрета = Отправитель.ДополнительныеСвойства.НепринятыеПоДатеЗапрета;
		КонецЕсли;
		НепринятыеПоДатеЗапрета.Вставить(СсылкаНаОбъект, ТипВерсииОбъекта);
		
		СведенияОВерсииОбъекта = Новый Структура;
		СведенияОВерсииОбъекта.Вставить("АвторВерсии", ОбщегоНазначения.МенеджерОбъектаПоСсылке(Отправитель.Ссылка).НайтиПоКоду(Отправитель.Код));
		СведенияОВерсииОбъекта.Вставить("ТипВерсииОбъекта", ТипВерсииОбъекта);
		СведенияОВерсииОбъекта.Вставить("Комментарий", "");
		СведенияОВерсииОбъекта.Вставить("ПредупреждениеСинхронизации", СтрокаСообщенияОбОшибке);
		
		Если ОбщегоНазначения.ЭтоДокумент(ЭлементДанных.Метаданные())
			И ТипВерсииОбъекта = "НепринятыйПоДатеЗапретаОбъектНеСуществуетВБазе" Тогда
			СвойствоПроведен = Новый Структура("Проведен", Ложь);
			ЗаполнитьЗначенияСвойств(ЭлементДанных, СвойствоПроведен);
		КонецЕсли;
		
		ПриСозданииВерсииОбъекта(ЭлементДанных, СведенияОВерсииОбъекта, СсылкаСуществует, Отправитель);
		
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//   Объект - СправочникОбъект, ДокументОбъект, и т.п - элемент данных.
//   МетаданныеОбъекта - ОбъектМетаданных - метаданные элемента данных.
//   ЗаписатьОбъект - Булево - Истина, если было выполнено замещение объекта этой ИБ полученным объектом.
//   ЭтоСсылочныйТип - Булево - Истина, если объект ссылочного типа.
//
Процедура ЗарегистрироватьПредупреждениеОКоллизииВЖурналеРегистрации(Объект, МетаданныеОбъекта, ЗаписатьОбъект, ЭтоСсылочныйТип)
	
	Если ЗаписатьОбъект Тогда
		
		ТекстПредупрежденияЖР = НСтр("ru = 'Возник конфликт изменений объектов.
		|Объект этой информационной базы был заменен версией объекта из второй информационной базы.'");
		
	Иначе
		
		ТекстПредупрежденияЖР = НСтр("ru = 'Возник конфликт изменений объектов.
		|Объект из второй информационной базы не принят. Объект этой информационной базы не изменен.'");
		
	КонецЕсли;
	
	Данные = ?(ЭтоСсылочныйТип, Объект.Ссылка, Неопределено);
		
	ЗаписьЖурналаРегистрации(ОбменДаннымиСервер.СобытиеЖурналаРегистрацииОбменДанными(),
		УровеньЖурналаРегистрации.Предупреждение, МетаданныеОбъекта, Данные, ТекстПредупрежденияЖР);
	
КонецПроцедуры

// Параметры:
//   Объект - Произвольный
//   МетаданныеОбъекта - ОбъектМетаданных
//   ЭтоСсылочныйТип - Булево
//   СсылкаСуществует - Булево
//   ОбъектВБазе - ЛюбаяСсылка
//               - Неопределено
//
Функция ДанныеОбъектаСтрокойДоИзменения(Объект, МетаданныеОбъекта, ЭтоСсылочныйТип, СсылкаСуществует, ОбъектВБазе)
	
	// Возвращаемое значение функции.
	СтрокаОбъекта = "";
	
	Если ЭтоСсылочныйТип Тогда
		
		Если СсылкаСуществует Тогда
			
			// Получаем представление объекта из ИБ по ссылке.
			СтрокаОбъекта = ОбщегоНазначения.ЗначениеВСтрокуXML(ОбъектВБазе);
			
		Иначе
			
			СтрокаОбъекта = НСтр("ru = 'Объект удален'");
			
		КонецЕсли;
		
	ИначеЕсли ОбщегоНазначения.ЭтоКонстанта(МетаданныеОбъекта) Тогда
		
		// Получаем значение константы из ИБ.
		СтрокаОбъекта = XMLСтрока(Константы[МетаданныеОбъекта.Имя].Получить());
		
	Иначе // Набор записей
		
		СтарыйНаборЗаписей = НаборЗаписей(Объект);
		СтрокаОбъекта = ОбщегоНазначения.ЗначениеВСтрокуXML(СтарыйНаборЗаписей);
		
	КонецЕсли;
	
	Возврат СтрокаОбъекта;
	
КонецФункции

Функция ДанныеОбъектаСтрокойПослеИзменения(Объект, МетаданныеОбъекта)
	
	// Возвращаемое значение функции.
	СтрокаОбъекта = "";
	
	Если ОбщегоНазначения.ЭтоКонстанта(МетаданныеОбъекта) Тогда
		
		СтрокаОбъекта = XMLСтрока(Объект.Значение);
		
	Иначе
		
		СтрокаОбъекта = ОбщегоНазначения.ЗначениеВСтрокуXML(Объект);
		
	КонецЕсли;
	
	Возврат СтрокаОбъекта;
	
КонецФункции

#КонецОбласти

#КонецОбласти